Silverlight: переключение визуальных состояний CustomVisualStateManager в коде

Я пытался решить следующую проблему: при создании пользовательских анимаций для различных визуальных состояний в Expression Blend 3, которые изменяют размер / непрозрачность нескольких элементов в сетке, он создает группы визуальных состояний в самой сетке, а не в стиле элемента управления и определяет его как CustomVisualStateManager.

<Grid x:Name="LayoutRoot" Background="White" Height="500" HorizontalAlignment="Left" VerticalAlignment="Top" Width="500">       
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MyVisualStateGroup">
    <VisualStateGroup.Transitions>
    <VisualTransition GeneratedDuration="00:00:00.3000000">
        <VisualTransition.GeneratedEasingFunction>
            <CircleEase EasingMode="EaseIn"/>
    </VisualTransition.GeneratedEasingFunction>
    </VisualTransition>
    </VisualStateGroup.Transitions>
    <VisualState x:Name="State1"/>
    <VisualState x:Name="State2">
        <Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="myBox" Storyboard.TargetProperty="(FrameworkElement.Height)">
            <EasingDoubleKeyFrame KeyTime="00:00:00" Value="360"/>
<!-- omitting other storyboard animations here for clarity -->                      
                </Storyboard>
    </VisualState>
    </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
    <ic:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>

<!-- omitting other grid elements here for clarity -->

</Grid>

Со мной все в порядке, но проблема в том, что я не могу переключать состояния в коде, когда пытаюсь

VisualStateManager.GoToState(this, "State1", true);

ничего не происходит, потому что сам элемент управления не определил эти визуальные состояния, как показано

VisualStateManager.GetVisualStateGroups(this);

Если я попробую

VisualStateManager.GetVisualStateGroups(LayoutRoot);

это показывает именно то, что мне нужно. Но я не могу передать LayoutRoot VisualStateManager, потому что ему нужен аргумент типа Control, а Grid - нет. Мой вопрос - как я могу получить доступ / изменить состояния этого CustomVisualStateManager в коде позади?

1 ответ

Решение

CustomVisualStateManager только там, когда вы включаете FluidLayout. Если в вашем проекте не используется морфинг макета (т. Е. Вы пытаетесь использовать состояния для плавной анимации из одного макета в другой), вы можете отключить его. Наличие собственного VSM не должно иметь никакого значения в использовании VSM.

Разметка визуального состояния всегда находится внутри контейнера верхнего уровня, так что это совершенно нормально. Кстати, это может быть просто опечатка в вашем образце, но код, который вы показываете, на самом деле пытается установить состояние, в котором ничего нет, так что это может не быть желаемым результатом.

В противном случае вызов VisualStateManager.GoToState в UserControl должен работать. Вот пример, который я только что сделал, который работает:

Это простой пример приложения Silverlight с главной страницей и пользовательским элементом управления, который я добавил на главную страницу. Главная страница действительно проста:

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SLStateTest"
x:Class="SLStateTest.MainPage"
Width="640" Height="480">

<Grid x:Name="LayoutRoot" Background="White">
    <local:UserControl1 x:Name="TestControl" Height="100" HorizontalAlignment="Left" Margin="24,32,0,0" VerticalAlignment="Top" Width="100"/>
    <Button Height="40" HorizontalAlignment="Left" Margin="192,32,0,0" VerticalAlignment="Top" Width="104" Content="State 1" Click="OnClick"/>
    <Button Height="40" HorizontalAlignment="Left" Margin="192,76,0,0" VerticalAlignment="Top" Width="104" Content="State 2" Click="OnClickState2"/>
</Grid></UserControl>

Есть экземпляр моего пользовательского контроля и две кнопки. Посмотрим, что кнопки делают через секунду. Сначала давайте посмотрим на UserControl (UserControl1):

<UserControl
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"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
x:Class="SLStateTest.UserControl1"
d:DesignWidth="280" d:DesignHeight="264">

<Grid x:Name="LayoutRoot" Background="#FF6FFE22">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="Test" ic:ExtendedVisualStateManager.UseFluidLayout="True">
            <VisualState x:Name="State1">
                <Storyboard>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                        <EasingColorKeyFrame KeyTime="00:00:00" Value="#FF003AFF"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="State2">
                <Storyboard>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                        <EasingColorKeyFrame KeyTime="00:00:00" Value="#FFFF0202"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <VisualStateManager.CustomVisualStateManager>
        <ic:ExtendedVisualStateManager/>
    </VisualStateManager.CustomVisualStateManager>
</Grid></UserControl>

Как видите, в одной группе визуальных состояний определены два визуальных состояния, которые просто устанавливают цвет в корне макета пользовательского элемента управления.

Две кнопки на главной странице связаны с обработчиками событий, которые выглядят следующим образом:

private void OnClick(object sender, System.Windows.RoutedEventArgs e)
    {
        // TODO: Add event handler implementation here.
        VisualStateManager.GoToState(TestControl, "State1", true);
    }

    private void OnClickState2(object sender, System.Windows.RoutedEventArgs e)
    {
        // TODO: Add event handler implementation here.
        TestControl.SetState();
    }

Первый просто вызывает VisualStateManager.GoToState в UserControl на странице. Второй вызывает функцию iside пользовательского элемента управления, которая делает то же самое. Я просто использовал оба метода, чтобы показать, что оба варианта доступны - вы можете вызвать VSM.GoToState снаружи или изнутри UC. Метод SetState() пользовательского элемента управления выглядит следующим образом:

public void SetState()
    {
        VisualStateManager.GoToState(this, "State2", true);
    }

Когда вы запустите приложение, пользовательский элемент управления сначала будет отображаться в его базовом состоянии, которое зеленого цвета. Когда вы нажимаете кнопку State1, она переходит в State1, который устанавливает UC в синий цвет, вызывая VSM.GoToState() снаружи. Когда вы нажимаете кнопку State 2, она становится красной, вызывая VSM изнутри.

Из отрывков, которые вы разместили, я не вижу, что идет не так, если не считать одной проблемы, о которой я упоминал в начале. Тем не менее, мой маленький образец может помочь вам увидеть, что отличается в вашем случае.

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

Другие вопросы по тегам