VisualStateManager.GoToState(Control, String, Boolean) 方法

定义

通过按名称请求新的 VisualState ,在两种状态之间转换控件。

public:
 static bool GoToState(Control ^ control, Platform::String ^ stateName, bool useTransitions);
 static bool GoToState(Control const& control, winrt::hstring const& stateName, bool const& useTransitions);
public static bool GoToState(Control control, string stateName, bool useTransitions);
function goToState(control, stateName, useTransitions)
Public Shared Function GoToState (control As Control, stateName As String, useTransitions As Boolean) As Boolean

参数

control
Control

要进行状态过渡的控件。

stateName
String

Platform::String

winrt::hstring

要转换到的状态。

useTransitions
Boolean

bool

如果为 true ,则使用 VisualTransition 在状态之间转换。 如果为 false ,则使用转换跳过并直接转到请求的状态。 默认值为 false

返回

Boolean

bool

如果控件成功转换为新状态,或已在使用该状态,则为 true;否则为 false

示例

此示例演示使用 GoToState 方法在状态之间转换的控制逻辑。

private void UpdateStates(bool useTransitions)
{
    if (Value >= 0)
    {
        VisualStateManager.GoToState(this, "Positive", useTransitions);
    }
    else
    {
        VisualStateManager.GoToState(this, "Negative", useTransitions);
    }

    if (isFocused)
    {
        VisualStateManager.GoToState(this, "Focused", useTransitions);
    }
    else
    {
        VisualStateManager.GoToState(this, "Unfocused", useTransitions);
    }

}
Private Sub UpdateStates(ByVal useTransitions As Boolean)
    If Value >= 0 Then
        VisualStateManager.GoToState(Me, "Positive", useTransitions)
    Else
        VisualStateManager.GoToState(Me, "Negative", useTransitions)
    End If

    If isFocused Then
        VisualStateManager.GoToState(Me, "Focused", useTransitions)
    Else
        VisualStateManager.GoToState(Me, "Unfocused", useTransitions)
    End If

End Sub
<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:NumericUpDownCustomControl"
    >
    <Style TargetType="local:NumericUpDown">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:NumericUpDown">
                    <Grid  Margin="3" 
                Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="ValueStates">
                                
                                <!--Make the Value property red when it is negative.-->
                                <VisualState x:Name="Negative">
                                    <Storyboard>
                                        <ColorAnimation To="Red"
                                    Storyboard.TargetName="TextBlock" 
                                    Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)"/>
                                    </Storyboard>
                                </VisualState>
                                <!--Return the control to its initial state by
                    return the TextBlock Foreground to its 
                    original color.-->
                                <VisualState x:Name="Positive" />
                            </VisualStateGroup>

                            <VisualStateGroup x:Name="FocusStates">
                                <!--Add a focus rectangle to highlight the entire control
                    when it has focus.-->
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual" 
                                                   Storyboard.TargetProperty="Visibility" Duration="0">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <!--Return the control to its initial state by
                    hiding the focus rectangle.-->
                                <VisualState x:Name="Unfocused"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>

                            <Border BorderThickness="1" BorderBrush="Gray" 
                    Margin="7,2,2,2" Grid.RowSpan="2" 
                    Background="#E0FFFFFF"
                    VerticalAlignment="Center" 
                    HorizontalAlignment="Stretch">
                                <TextBlock x:Name="TextBlock" TextAlignment="Center" Padding="5"
                           Foreground="{TemplateBinding Foreground}"/>

                            </Border>

                            <RepeatButton Content="Up" Margin="2,5,5,0" 
                          x:Name="UpButton"
                          Grid.Column="1" Grid.Row="0"
                          Foreground="Green"/>
                            <RepeatButton Content="Down" Margin="2,0,5,5" 
                          x:Name="DownButton"
                          Grid.Column="1" Grid.Row="1" 
                          Foreground="Green"/>

                            <Rectangle Name="FocusVisual" Grid.ColumnSpan="2" Grid.RowSpan="2" 
                       Stroke="Red" StrokeThickness="1"  
                       Visibility="Collapsed"/>
                        </Grid>

                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
</ResourceDictionary>

注解

控件逻辑使用此方法。 通常,只有在编写自定义控件时,或者对视图状态使用应用级逻辑 ((例如刷新应用内容以更改应用窗口大小或方向) )时才需要它。

调用此方法时,应有一个 VisualState ,其 x:Name 值与 stateName 值匹配,控件标识的控件的控件模板中的某个 位置,或作为应用的资源。 如果没有,则不会收到异常,但返回值为 falsestateName 命名的状态可以位于指定控件模板中的任何 VisualStateGroup 元素中。 由你来跟踪哪些状态处于哪个 VisualStateGroup ,并知道在从该组指定新状态时卸载哪些状态。

通常,使用 GoToState 时包含按名称引用的视觉状态的 ControlTemplate 不是为该控件实例专门定义。 相反,视觉状态来自默认控件样式,该样式作为该控件的所有实例的隐式样式加载。 有关隐式样式概念的详细信息,请参阅 快速入门:控件模板

VisualStateManager 为控件作者和将自定义模板应用于控件的应用开发人员支持两个重要功能:

  • 控件作者或应用开发人员使用 VisualStateManager.VisualStateGroups 附加属性,将 VisualStateGroup 对象元素添加到 XAML 中的控件模板定义的根元素。 在 VisualStateGroup 元素中,每个 VisualState 表示控件的离散视觉状态。 每个 VisualState 都有一个代表可由用户更改或由控件逻辑更改的 UI 状态的名称。 VisualState 主要由情节提要组成。 此 情节提要 面向当控件处于该视觉状态时应应用的单个依赖属性值。
  • 控件作者或应用开发人员通过调用 VisualStateManager 的静态 GoToState 方法在这些状态之间转换。 每当控件逻辑处理指示状态更改的事件或控件逻辑自行启动状态更改时,控件作者就会执行此操作。 控件定义代码更常见地执行此操作,而不是应用代码,以便应用代码默认存在所有可能的视觉状态及其转换和触发条件。 或者,应用代码正在更改视觉状态,以管理应用级视图状态,以响应用户驱动的对main应用窗口的大小或方向的更改。

调用 GoToState 更改控件的可视状态时, VisualStateManager 将执行以下操作:

  • 首先确定是否存在与 stateName 匹配的状态。 如果没有,则不会发生任何操作,并且 方法返回 false
  • 如果存在由 stateName 命名的 VisualState,并且具有 Storyboard,则情节提要将开始。
  • 如果控件在新请求的状态之前从同一 VisualStateGroup 使用的 VisualState 具有 Storyboard,该情节提要将停止。 除了新 VisualState 向其应用动画的特定属性外,控件将还原到控件模板及其合成中最初加载的状态。

如果控件已在作为 stateName 请求的 VisualState 中,则 GoToState 将返回 true,但 (不会) 重启情节提要的操作。

常见的控件实现模式是定义控件类的单个私有方法,用于处理控件的所有可能的 VisualState 更改。 使用哪个视觉状态是通过检查控件的属性确定的。 这些属性可以是公共的,也可以是私有的。 属性的值由事件(例如 OnGotFocus)的控制逻辑中的处理程序进行调整,并在设置视觉状态之前立即进行实时检查。 本主题中的代码示例使用此实现模式。 或者,可以从事件处理程序内部、控件事件处理程序替代 (OnEvent 方法) ,或从所有可能动力调用的帮助程序方法调用 GoToState,以 (更改用户驱动的事件、自动化事件、初始化逻辑) 的状态。

还可以从 PropertyChangedCallback 实现中为自定义依赖属性调用 GoToState。

视觉状态和转换

除了视觉状态,视觉状态模型还包括转换。 切换是由 情节提要 控制的动画操作,在状态更改时,这些动作在每个视觉状态之间发生。 对于由控件的视觉状态集定义的开始状态和结束状态的每种组合,可以以不同的方式定义转换。 转换由 VisualStateGroupTransitions 属性定义,通常在 XAML 中定义。 大多数默认控件模板不定义转换,在这种情况下,状态之间的转换会立即发生。 有关详细信息,请参阅 VisualTransition

还可以定义 VisualTransition ,使其产生隐式转换。 对于 VisualTransition“从”或“”视觉状态中动画,并且在整个状态更改中具有不同值的动画,任何依赖属性都可以使用隐式过渡动画进行动画处理。 此生成的动画在此类属性的 From 状态值和 To 状态值之间使用内插转换。 隐式过渡动画的持续时间为 VisualTransitionGeneratedDuration 值所声明的时间。 隐式转换仅适用于 双精度值、 颜色 值或 值的属性。 换句话说,属性必须能够使用 DoubleAnimation、PointAnimationColorAnimation 进行隐式动画处理。 有关详细信息,请参阅 GeneratedDuration

视觉状态更改事件

当控件开始根据 GoToState 调用的请求转换状态时,CurrentStateChanging 将触发。 如果 VisualTransition 应用于状态更改,则转换开始时会发生此事件。

CurrentStateChanged 在控件处于 GoToState 调用请求的状态后触发,就像新的 Storyboard 开始一样。 新情节提要完成时不会触发任何事件。

如果未应用 VisualTransitionCurrentStateChangingCurrentStateChanged 会快速连续触发,但如果两者都发生,则保证按该顺序运行。

但是,如果状态更改转换被新的 GoToState 调用中断,则不会为第一次状态转换引发 CurrentStateChanged 事件。 为下一个请求的状态更改触发新的事件系列。

不为视觉状态更改调用 OnApplyTemplate。 仅针对控件初始加载到 XAML UI 中调用 OnApplyTemplate

归因自定义控件的命名视觉状态

如果要定义在其控件模板 XAML 中具有视觉状态的自定义控件,则最佳做法是将控件类归为属性,以指示控件使用者哪些视觉状态可用。 为此,请在控件定义代码的类级别应用一个或多个 TemplateVisualState 属性。 每个属性都应指定状态的 x:Name 属性,该属性是控件使用者在 GoToState 调用中传递以使用该视觉状态的 stateName 值。 如果 VisualStateVisualStateGroup 的一部分,则应在属性定义中指明这一点。

一个相关概念是,控件作者应使用 TemplatePartAttribute 将关键控件部件的名称归为属性。 如果控件使用者希望在应用模板后从模板范围访问命名部件,这将非常有用。 TemplateVisualStateAttributeTemplatePartAttribute 组合帮助定义控件的控件协定。

自定义 VisualStateManager

作为高级方案,可以从 VisualStateManager 派生并更改默认的 GoToState 行为。 派生类应重写受保护的 GoToStateCore 方法。 自定义 VisualStateManager 的任何实例在调用其 GoToState 方法时都使用此 核心 逻辑。

应用视图状态的视觉状态

视觉状态不一定适用于自定义控件。 可以通过设置 Template 属性来替换默认模板的任何控件实例使用新控件模板中的视觉状态。 若要进行此设置,必须定义计划用作 中的Page.ResourcesApplication.Resources样式资源的控件模板和视觉状态。 始终最好从默认模板的副本开始,仅修改模板的某些方面,甚至只修改某些视觉状态,并保留基本组合。 有关详细信息,请参阅快速入门:控件模板

视觉状态可用于更改 页面或页面中 控件的属性,以考虑应用窗口方向。 组合或控件的布局相关属性值可能会根据整体方向是纵向还是横向而更改。 有关 GoToState 的此方案的详细信息,请参阅 快速入门:为不同窗口大小设计应用

非控件元素的视觉状态

视觉状态有时对于想要更改 UI 的某些区域(不是 直接作为 Control 子类)的状态的方案非常有用。 无法直接执行此操作,因为 GoToState 方法的 控件 参数需要 Control 子类,该类引用 VisualStateManager 作用的对象。 PageControl 子类,很少在没有 PageWindow.Content 根不是 Control 子类的上下文中显示 UI。 建议将自定义 UserControl 定义为 Window.Content 根目录或要将状态应用于 ((例如 面板) )的其他内容的容器。 然后,可以在 UserControl 上调用 GoToState 并应用状态,而不考虑其余内容是否为 控件。 例如,可以将视觉状态应用于 UI,否则该 UI 只包含 SwapChainPanel ,前提是将它放置在 UserControl 中,并声明了适用于父 UserControl 或模板的已命名 SwapChainPanel 部分的属性的命名状态。

适用于

另请参阅