【问题标题】:VisualStateManager fails to start animation on UserControlVisualStateManager 无法在 UserControl 上启动动画
【发布时间】:2013-06-26 06:28:07
【问题描述】:

我正在尝试在 Windows Phone 7 Silverlight 项目中使用 VisualStateManager 在 UserControl 上启动动画,但它不起作用。 GoToState 只是一直返回 false。

代码包含一个 VisualState-behaviour,当数据上下文上的 State-property 发生更改时运行 GoToState,这发生在单击 UI 中的按钮时:

我做错了什么?

XAML:

    <Grid>
        <UserControl x:Name="_testSubject" l:VisualStates.CurrentState="{Binding State}" />
        <Button VerticalAlignment="Bottom" Content="Change state" Click="Button_Click" />
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState x:Name="State2">
                    <Storyboard>
                        <ColorAnimation From="Red" To="Green" Duration="0:0:10" Storyboard.TargetProperty="Background" Storyboard.TargetName="_testSubject" />
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Grid>

C#:

public class Test : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string name) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name)); }
    string _state;
    public string State { get { return _state; } set { _state = value; OnPropertyChanged("State"); } }
}

public static class VisualStates
{
    public static readonly DependencyProperty CurrentStateProperty =
        DependencyProperty.RegisterAttached("CurrentState", typeof(String), typeof(VisualStates), new PropertyMetadata(TransitionToState));

    public static string GetCurrentState(DependencyObject obj)
    {
        return (string)obj.GetValue(CurrentStateProperty);
    }

    public static void SetCurrentState(DependencyObject obj, string value)
    {
        obj.SetValue(CurrentStateProperty, value);
    }

    private static void TransitionToState(object sender, DependencyPropertyChangedEventArgs args)
    {
        Control c = sender as Control;
        if (c != null)
        {
            bool b = VisualStateManager.GoToState(c, (string)args.NewValue, false);
        }
        else
        {
            throw new ArgumentException("CurrentState is only supported on the Control type");
        }
    }

public partial class MainPage : PhoneApplicationPage
{
    public MainPage() { InitializeComponent(); }

    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
    {
        _testSubject.DataContext = new Test();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ((Test)_testSubject.DataContext).State = "State2";
    }
}

【问题讨论】:

    标签: c# .net silverlight windows-phone-7 visualstatemanager


    【解决方案1】:

    只是一个疯狂的猜测,但它可能是在错误的线程中执行的吗?您可能希望使用调度程序在正确的 (UI) 线程上执行它。

    GoToState 是否在 Button_Click 函数中起作用?

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        bool b = VisualStateManager.GoToState(this, "State2", false);
    }
    

    当您执行代码时,会调用 TransitionToState。

    这将排除任何其他问题。

    更新

    以下内容对我有用。我在设置背景时遇到了一些问题。首先,这对 UserControl 没有任何影响,其次,无法使用 Color 动画更改背景,这就是我更改不透明度的原因。

    MainPage.xaml

    <Grid x:Name="ContentPanel"
          Grid.Row="1"
          Margin="12,0,12,0">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <l:TestControl x:Name="_testSubject"
                       Grid.Row="0"
                       l:VisualStates.CurrentState="{Binding State}" />
    
        <UserControl x:Name="_test2Subject"
                     Height="100"
                     Grid.Row="1"
                     l:VisualStates.CurrentState="{Binding State}">
            <Grid x:Name="aLayoutRoot"
                  Background="Wheat">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="State2">
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="aLayoutRoot"
                                                 Storyboard.TargetProperty="Opacity"
                                                 From="1"
                                                 To="0"
                                                 Duration="0:0:2"
                                                 AutoReverse="True" />
                            </Storyboard>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
            </Grid>
        </UserControl>
    
        <Button Click="Button_Click"
                Content="Click"
                Grid.Row="2" />
    
    
    </Grid>
    

    TestControl.xaml

    <UserControl x:Class="PhoneApp1.TestControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        d:DesignHeight="480" d:DesignWidth="480">
    
        <Grid x:Name="LayoutRoot" Background="Wheat">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="State2">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="LayoutRoot"
                                             Storyboard.TargetProperty="Opacity"
                                             From="1"
                                             To="0"
                                             Duration="0:0:2"
                                             AutoReverse="True" />
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </UserControl>
    

    Test.cs / TransitionToState 方法

    private static void TransitionToState(object sender, DependencyPropertyChangedEventArgs args)
    {
        UserControl c = sender as UserControl;
        if (c != null && args.NewValue != null)
        {
            bool b = VisualStateManager.GoToState(c, (string)args.NewValue, true);
            var a = b;
        }
    }
    

    MainPage.cs

    public MainPage()
    {
        InitializeComponent();
    
        _testSubject.DataContext = new Test();
        _test2Subject.DataContext = new Test();
    
    }
    
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        ((Test)_testSubject.DataContext).State = "State2";
        ((Test)_test2Subject.DataContext).State = "State2"; 
    }
    

    我还建议使用 ControlTemplates 来分配 VisualStates,而不是直接在控件上定义它们。这将为您提供更大的灵活性、更好的维护等。

    希望这会有所帮助。

    【讨论】:

    • GoToState 仍然返回 false,即使在 Button_Click 中也是如此。
    • 奇怪,我什至不能在用户控件中放置一个网格。它不支持它所说的直接内容。尝试使用 ContentControl 代替,但这并没有解决问题。 GoToState 仍然返回 false。不过感谢您的努力。我改用另一种方法。
    • 但是将它放在单独的 UserControl 中效果更好,包括动画!很奇怪。
    • 我需要注意我使用的是最新的'Mango' SDK。所以这可能解释了一些差异。
    【解决方案2】:

    我遇到了类似的问题,我找到了一个对我有帮助的解决方案,并且可能有人觉得它有用 如果用户控件托管在 layoutawarepage 中

    <my:usercontrole Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates" />
    

    否则你将不得不遵循(可以在布局感知页面中找到示例)

    • 在 sizechanged 上创建事件处理程序

    • 在事件处理程序中使用 ApplicationView.Value 检查视图状态

    • 使用 VisualStateManager.GoToState 移动到该状态

    编辑:抱歉误会我以为是winRT App

    【讨论】:

      猜你喜欢
      • 2016-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多