Udostępnij za pośrednictwem


VisualStateManager.GoToState(Control, String, Boolean) Method

Definition

Transitions a control between two states, by requesting a new VisualState by name.

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

Parameters

control
Control

The control to transition between states.

stateName
String

Platform::String

winrt::hstring

The state to transition to.

useTransitions
Boolean

bool

true to use a VisualTransition to transition between states. false to skip using transitions and go directly to the requested state. The default is false.

Returns

Boolean

bool

true if the control successfully transitions to the new state, or was already using that state; otherwise, false.

Examples

This example demonstrates control logic that uses the GoToState method to transition between states.

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>

Remarks

This method is used by control logic. You typically only need it if you are writing a custom control, or if you are using app-level logic for view states (such as refreshing your app content for changes in app window size or orientation).

When you call this method, there is expected to be a VisualState with an x:Name value that matches your stateName value, somewhere in the control template for the control identified by control, or as a resource for your app. If there isn't, you don't get exceptions, but the return value will be false. The state named by stateName can be in any of the VisualStateGroup elements in the template for the specified Control. It's up to you to keep track of which states are in which VisualStateGroup and knowing which state gets unloaded when you specify a new state from that group.

Typically the ControlTemplate that contains the visual states as referenced by name when using GoToState is not specifically defined for that control instance. Instead the visual states are from the default control style that's loaded as the implicit style for all instances of that control. For more info on the implicit style concept, see XAML Control templates.

VisualStateManager supports two important features for control authors, and for app developers who are applying a custom template to a control:

  • Control authors or app developers add VisualStateGroup object elements to the root element of a control template definition in XAML, using the VisualStateManager.VisualStateGroups attached property. Within a VisualStateGroup element, each VisualState represents a discrete visual state of a control. Each VisualState has a name that is representative of a UI state that can be changed by the user, or changed by control logic. A VisualState consists mainly of a Storyboard. This Storyboard targets individual dependency property values that should be applied whenever the control is in that visual state.
  • Control authors or app developers transition between these states by calling the static GoToState method of VisualStateManager. Control authors do this whenever the control logic handles events that indicate a change of state, or control logic initiates a state change by itself. It's more common for control definition code to do this rather than app code, so that all the possible visual states and their transitions and trigger conditions are there by default for app code. Or, it's the app code that is changing visual states, to manage app-level view states in response to user-driven changes to the size or orientation of the main app window.

When you call GoToState to change the visual state of a control, the VisualStateManager performs these actions:

  • First it's determined whether a state that matches stateName exists. If not, nothing happens and the method returns false.
  • If the VisualState as named by stateName exists, and has a Storyboard, the storyboard begins.
  • If the VisualState that the control was using from that same VisualStateGroup prior to the newly requested state has a Storyboard, that storyboard stops. Other than the specific properties that the new VisualState applies an animation to, the control reverts to the initially loaded states from the control template and its composition.

If the control is already in the VisualState requested as stateName, GoToState returns true, but there is otherwise no action (the storyboard won't be restarted).

A common control implementation pattern is to define a single private method of the control class that takes care of all possible VisualState changes for the control. Which visual state to use is determined by checking the control's properties. These properties might be public or private. Values of properties are adjusted by handlers in control logic for events such as OnGotFocus, and are checked just-in-time immediately before setting the visual state. The code example in this topic uses this implementation pattern. Alternatively, you can call GoToState for individual states from within event handlers, from control event handler overrides (the OnEvent methods), or from helper methods that are called by all possible impetus for changing states (user-driven events, automation events, initialization logic).

You might also call GoToState from within the PropertyChangedCallback implementation for a custom dependency property.

Visual states and transitions

In addition to the visual states, the visual state model also includes transitions. Transitions are animation actions controlled by a Storyboard that occur between each visual state when the state is changed. The transition can be defined differently for each combination of starting state and ending state as defined by your control's set of visual states. Transitions are defined by the Transitions property of VisualStateGroup and are usually defined in XAML. Most default control templates don't define transitions, and in this case the transitions between states happen instantaneously. For more info, see VisualTransition.

A VisualTransition can also be defined such that it produces an implicit transition. Any dependency property that is specifically targeted for animation in either the From orTo visual states of a VisualTransition and has different values across the state change can be animated with an implicit transition animation. This generated animation transitions between the From state value and the To state value of such a property using interpolation. The implicit transition animation lasts for the time stated by the GeneratedDuration value of a VisualTransition. Implicit transitions only apply to properties that are a Double, Color or Point value. In other words the property must be possible to implicitly animate using a DoubleAnimation, PointAnimation or ColorAnimation. For more info, see GeneratedDuration.

Events for visual state changes

CurrentStateChanging fires when the control begins to transition states as requested by the GoToState call. If a VisualTransition is applied to the state change, this event occurs when the transition begins.

CurrentStateChanged fires after the control is in the state as requested by the GoToState call, just as the new Storyboard begins. No event is fired on the new storyboard's completion.

If a VisualTransition is not applied, CurrentStateChanging and CurrentStateChanged fire in quick succession, but are guaranteed in that order if both occur.

However, if a state change transition is interrupted by a new GoToState call, the CurrentStateChanged event is never raised for the first state transition. A new event series is fired for the next requested state change.

OnApplyTemplate is not invoked for visual state changes. OnApplyTemplate is only invoked for the initial load of a control into a XAML UI.

Attributing a custom control's named visual states

If you are defining a custom control that has visual states in its control template XAML, it's a best practice to attribute the control class to indicate to control consumers which visual states are available. To do this, apply one or more TemplateVisualState attributes at the class level of your control definition code. Each attribute should specify the state's x:Name attribute, which is the stateName value a control consumer would pass in a GoToState call to use that visual state. If the VisualState is part of a VisualStateGroup, that should also be indicated in the attribute definition.

A related concept is that control authors should attribute the names of key control parts using TemplatePartAttribute. This is very helpful if control consumers want to access named parts from the template scope after the template is applied. TemplateVisualStateAttribute and TemplatePartAttribute combined help define the control contract for a control.

Custom VisualStateManager

As an advanced scenario, it is possible to derive from VisualStateManager and change the default GoToState behavior. The derived class should override the protected GoToStateCore method. Any instance of the custom VisualStateManager uses this Core logic when its GoToState method is called.

Visual states for app view states

Visual states aren't necessarily for custom controls. You can use visual states from new control templates that you apply to any Control instance where you're replacing the default template by setting the Template property. To set this up, you must define the control template and visual states that you're planning on using as a Style resource that's in either Page.Resources or Application.Resources. It's always best to start with a copy of the default template and modify only certain aspects of the template or even just modify some of the visual states and leave the basic composition alone. For more info, see XAML Control templates.

Visual states can be used to change properties of a Page or controls within the page to account for app window orientation. Your composition or your control's layout-related property values might change depending on whether the overall orientation is portrait or landscape. For more info about this scenario for GoToState, see Responsive layouts with XAML.

Visual states for elements that aren't controls

Visual states are sometimes useful for scenarios where you want to change the state of some area of UI that's not immediately a Control subclass. You can't do this directly because the control parameter of the GoToState method requires a Control subclass, which refers to the object that the VisualStateManager acts upon. Page is a Control subclass, and it's fairly rare that you'd be showing UI in a context where you don't have a Page, or your Window.Content root isn't a Control subclass. We recommend you define a custom UserControl to either be the Window.Content root or be a container for other content you want to apply states to (such as a Panel). Then you can call GoToState on your UserControl and apply states regardless of whether the rest of the content is a Control. For example you could apply visual states to UI that otherwise consists of just a SwapChainPanel so long as you placed that within your UserControl and declared named states that apply to the properties of the parent UserControl or of the named SwapChainPanel part of the template.

Applies to

See also