VisualStateManager не может запустить анимацию в UserControl - PullRequest
3 голосов
/ 21 августа 2011

Я пытаюсь запустить анимацию в UserControl с помощью VisualStateManager в проекте Windows Phone 7 Silverlight, но он не работает.GoToState просто продолжает возвращать false.

Код состоит из VisualState-поведения, которое запускает GoToState при изменении свойства State в текстовом тексте данных, что происходит при нажатии кнопки в пользовательском интерфейсе:

Что я делаю не так?

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";
    }
}

Ответы [ 2 ]

2 голосов
/ 22 августа 2011

просто дикое предположение, но может ли быть так, что оно выполняется не в том потоке? Возможно, вы захотите использовать диспетчер для выполнения его в правильном потоке (UI).

Работает ли GoToState в функции Button_Click?

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

И вызывается ли TransitionToState при выполнении вашего кода.

Это исключило бы любые другие проблемы.

UPDATE

Следующее работает для меня. У меня возникли некоторые проблемы с настройкой фона. Во-первых, это не влияет на UserControl, а во-вторых, невозможно изменить фон с помощью цветной анимации, поэтому я изменяю прозрачность.

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 вместо определения их непосредственно в элементе управления. Это даст вам больше гибкости, лучшего обслуживания и т. Д.

Надеюсь, это поможет.

0 голосов
/ 26 июня 2013

У меня была похожая проблема, я нашел решение, которое помогло мне, и, возможно, кто-то найдет его полезным, если usercontrol размещен на layoutawarepage

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

в противном случае вам придется выполнить следующее (пример может бытьнаходится на странице с информацией о разметке)

  • сделать обработчик событий для размера измененным

  • в обработчике событий проверить состояние представления с ApplicationView.Value

  • перейти в это состояние с помощью VisualStateManager.GoToState

Редактировать: Извините за недоразумение Я думал, что это WinRT App

...