VisualStateManager не запускает анимацию в UserControl

Я пытаюсь запустить анимацию в 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";
    }
}

person Andreas Zita    schedule 21.08.2011    source источник


Ответы (2)


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

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

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

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

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

ОБНОВЛЕНИЕ

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

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

person invalidusername    schedule 22.08.2011
comment
GoToState по-прежнему возвращает false даже в Button_Click. - person Andreas Zita; 22.08.2011
comment
Странно, я даже не могу поместить сетку в UserControl. Он говорит, что он не поддерживает прямой контент. Вместо этого пробовал использовать ContentControl, но это все равно не решило проблему. GoToState по-прежнему возвращает false. Тем не менее, спасибо за ваши усилия. Вместо этого я выбрал другой подход. - person Andreas Zita; 22.08.2011
comment
Но размещение его в отдельном UserControl сработало лучше, включая анимацию! Очень странный. - person Andreas Zita; 22.08.2011
comment
Я должен отметить, что я использую последнюю версию SDK Mango. Таким образом, это может объяснить некоторые различия. - person invalidusername; 22.08.2011

У меня была аналогичная проблема, я нашел решение, которое помогло мне и может быть кому-то полезно, если пользовательский элемент управления размещен на layoutawarepage

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

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

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

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

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

Изменить: извините за недоразумение, я подумал, что это приложение winRT

person Muhammad Alaa    schedule 25.06.2013