9. 可视化状态管理器

tech2023-01-23  57

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