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);
    }

}
<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:NamestateName 匹配,在 控件模板中的某个位置,该控件由 标识 control,或作为应用的资源。 如果没有,则不会收到异常,但返回值为 false。 由 命名stateName的状态可以位于指定控件的模板中的任何 VisualStateGroup 元素中。 由你来跟踪哪些状态处于哪个 VisualStateGroup 状态,并知道在从该组指定新状态时,哪个状态会被卸载。

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

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

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

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

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

如果控件已在作为 stateName 请求的 VisualState 中,GoToStatetrue返回 ,但不存在任何操作 (情节提要不会) 重启。

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

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

视觉状态和转换

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

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

视觉状态更改事件

当控件开始根据调用的请求转换状态时,CurrentStateChangingGoToState触发。 如果 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,自定义 VisualStateManager 的任何实例都使用此核心逻辑。

应用视图状态的视觉状态

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

视觉状态可用于更改 页面或页面中 控件的属性,以考虑应用窗口方向。 组合或控件的布局相关属性值可能会根据整体方向是纵向还是横向而更改。 有关 的此方案 GoToState的详细信息,请参阅 使用 XAML 的响应式布局

非控件元素的视觉状态

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

适用于

另请参阅