Silverlight:在代码隐藏中切换CustomVisualStateManager的VisualStates

时间:2009-11-23 14:09:48

标签: c# silverlight silverlight-3.0 expression-blend visualstatemanager

我一直在努力解决以下问题: 在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 个答案:

答案 0 :(得分:3)

启用FluidLayout时,CustomVisualStateManager就在那里。除非您的项目中涉及布局变形(即您尝试使用状态从一个布局平滑地动画制作到另一个布局),否则可以将其关闭。自定义VSM的存在不应对VSM的使用产生任何影响。

可视状态标记始终位于顶级容器内,因此完全正常。顺便说一下,这可能只是你样本中的一个拼写错误,但你显示的代码实际上试图设置一个没有任何内容的状态,这可能不是理想的结果。

否则,在UserControl上调用VisualStateManager.GoToState应该可以工作。这是我刚刚制作的一个例子:

这是一个简单的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();
    }

第一个只是在页面上的UserControl上调用VisualStateManager.GoToState。第二个调用用户控件的函数iside做同样的事情。我只是使用两种方法来显示两个选项都可用 - 您可以从UC的外部或内部调用VSM.GoToState。用户控件的SetState()方法如下所示:

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

运行应用程序时,用户控件将首先显示为基本状态,即绿色。当你按状态1按钮时,它会转到State1,它通过从外面调用VSM.GoToState()将UC设置为蓝色。当您按下状态2按钮时,它会从内部调用VSM切换为红色。

从您发布的片段中,我看不出有什么问题,缺少我在开头提到的一个问题。但是,我的小样本可能会帮助您了解您的情况有何不同。

希望有帮助...