9. 可视化状态管理器

本章前面的"控件模板"中,介绍了如何创建控件模板,自定义控件的外观。其中还缺了些什么,使用按钮的默认模板,按钮会响应鼠标的移动和单击,当鼠标移动到按钮或单击按钮时,按钮的外观是不同的。这种外观变化通过可视化状态和动画来处理,由可视化状态管理器(VisualStateManager)控制。

本节介绍如何改变按钮样式,来响应鼠标的移动和单击,还描述了如何创建自定义状态,当几个控件应该切换到禁用状态时,例如进行一些后台处理时,这些自定义状态用于处理完整页面的变化。

对于XAML元素,可以定义可视化状态、状态组、和状态,指定状态的特定动画。状态组允许同时有多个状态。对于一组,一次只能有一个状态。然而,另一组的另一个状态可以在同一时间激活。例如,按钮的状态和状态组。按钮控件定义了状态组CommonStates和FocusStates。用FocusStates定义的状态是Focused、UnFocused和PointerFocused,CommonStates组定义了状态Normal、PointerOver、Pressed和Disabled。有了这些选项,多个状态可以同时激活,但一个状态组内总是只有一个状态是激活的。例如,按钮可以是Focused和Normal状态。它也可以是Focused和Pressed状态,还可以定义定制的状态和状态组。

下面看看具体的例子。

1. 用控件模板预定义状态

下图利用先前创建的自定义控件模板,样式化按钮控件,使用可视化状态改进它。为此,一个简单的方法是使用Microsoft Blend for Visual Studio,下图显示了状态窗口,选择控件模板时就会显示该窗口。在这里可以看到控件的可用状态,并基于这些状态记录变化。

之前的按钮模板改为可视化状态:Pressed、Disabled和PointerOver。在状态中,Storyboard定义了一个ColorAnimation来改变椭圆的Fill属性的颜色:

    <Page.Resources>
        <Style x:Key="RoundedGelButton" TargetType="Button">
            <Setter Property="Width" Value="100"/>
            <Setter Property="Height" Value="100"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <ColorAnimation Duration="0" To="#FFC8CE11"
                                                            Storyboard.TargetName="GelBackground"
                                                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                                            d:IsOptimized="true"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ColorAnimation Duration="0" To="#FF606066"
                                                            Storyboard.TargetName="GelBackground"
                                                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                                            d:IsOptimized="True"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <ColorAnimation Duration="0" To="#FF0F9D3A"
                                                            Storyboard.TargetName="GelBackground"
                                                            Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                                            d:IsOptimized="True"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Ellipse x:Name="GelBackground" StrokeThickness="0.5" Fill="Black">
                                <Ellipse.Stroke>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="#ff7e7e7e"/>
                                        <GradientStop Offset="1" Color="Black"/>
                                    </LinearGradientBrush>
                                </Ellipse.Stroke>
                            </Ellipse>
                            <Ellipse Margin="15,5,15,50">
                                <Ellipse.Fill>
                                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                        <GradientStop Offset="0" Color="#aaffffff"/>
                                        <GradientStop Offset="1" Color="Transparent"/>
                                    </LinearGradientBrush>
                                </Ellipse.Fill>
                            </Ellipse>
                            <ContentPresenter x:Name="GelButtonContent" VerticalAlignment="Center" HorizontalAlignment="Center"
                                              Content="{TemplateBinding Content}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>

现在运行应用程序,可以看到颜色随着鼠标的移动和单击而变化。

2. 定义自定义状态

使用VisualStateManager可以定义定制的状态,使用VisualStateGroup和VisualState的状态可以定义定制的状态组。下面的代码片段在名为CustomStates的组内创建了Enabled和Disabled状态。该可视化状态管理器在主窗口的网格中定义。改变状态时,Button元素的IsEnabled属性使用DiscreteObjectKeyFrame动画立即改变:

    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CustomStates">
                <VisualState x:Name="Enabled"/>
                <VisualState x:Name="Disabled">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="button1"
                                                       Storyboard.TargetProperty="Control.IsEnabled">
                            <DiscreteObjectKeyFrame KeyTime="0">
                                <DiscreteObjectKeyFrame.Value>
                                    <x:Boolean>False</x:Boolean>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="button2"
                                                       Storyboard.TargetProperty="Control.IsEnabled">
                            <DiscreteObjectKeyFrame KeyTime="0">
                                <DiscreteObjectKeyFrame.Value>
                                    <x:Boolean>False</x:Boolean>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <StackPanel Spacing="10">
            <Button Content="Click Me!" Style="{StaticResource RoundedGelButton}"/>
            <Button x:Name="button1" Content="OnEnable" Click="OnEnable"/>
            <Button x:Name="button2" Content="OnDisable" Click="OnDisable"/>
        </StackPanel>
    </Grid>

3. 设置自定义的状态

现在需要设置状态。为此,可以调用VisualStateManager类的GoToState方法。在代码隐藏文件中,OnEnabled和OnDisabled方法是页面上两个按钮的Click事件处理程序:

        private void OnEnable(object sender, RoutedEventArgs e)
        {
            VisualStateManager.GoToState(this,"Enabled",useTransitions:true);
        }

        private void OnDisable(object sender, RoutedEventArgs e)
        {
            VisualStateManager.GoToState(this,"Disabled",useTransitions:true);
        }

在真实的应用程序中,可以以类似的方式更改状态,例如执行网络调用时,用户不应该处理页面内的一些控件。用户仍应被允许单击取消按钮。通过改变状态,还可以显示进度信息。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值