Search code examples
xamluwpwindows-runtime

Do the names of states in a VisualStateManager have meaning?


Are the names for states and VisualStateGroups in VisualStateManager arbitrary, or do they have deeper meaning?

They seem similar to pseudo-classes in CSS, in some ways (Button has CommonStates: Normal, PointerOver, Pressed, and Disabled, whereas CSS has :hover, :active, and ways of targeting disabled controls). But they are also different—Checkbox has (it seems) completely different states, like Checked, Unchecked, and Indeterminate.

As I develop my apps, how do I know which VisualStates are available? What happens if I use the wrong names?

Disclaimer: I work for Microsoft.


Solution

  • Do the names for states hold deeper meaning?

    Are the names for states and VisualStateGroups in VisualStateManager arbitrary, or do they have deeper meaning?

    The names for states and VisualStateGroups are indeed arbitrary, but they do have a deeper meaning.

    VisualStates in VisualStateManager are [representations of] the visual appearance of a UI element when it is in a specific state. They use Storyboards or Setters to represent arbitrary changes to a given Control (for example, make the background red). Control authors can call VisualStateManager.GoToState within their codebehind to activate a named VisualState.

    In this way, VisualState names are arbitrary: I could create a VisualState named CitelaosGreatState and activate it by calling GoToState(this, "CitelaosGreatState"). That's why there's such a variety of names—Buttons have the CommonStates you mentioned, while Checkboxes have completely different ones.

    However, for practical purposes, the VisualState names you choose are not arbitrary.

    If you are using a VisualStateManager to modify the look & feel of a default control (by overriding the ControlTemplate), you almost certainly want to pick VisualState and VisualStateGroup names that correspond exactly to the names in the original ControlTemplate (which you can find in the XAML designer or in generic.xaml). This is a matter of functionality: the implementers of, say, Button chose an arbitrary name for the VisualState that appears when you hover a Button—CommonStates PointerOver. The logic in their codebehind that handles hovering a Button calls GoToState(this, "PointerOver") (or some equivalent). If you want to customize that appearance, you have to provide a VisualState with that name.

    You can certainly also provide a cool state named CitelaosGreatState, or even Hover, but if the codebehind never calls GoToState with that same string, your state will never be activated, no matter the name.

    Of course, that means for completely custom controls (where you control both the VisualStateManager and calls to VisualStateManager.GoToState), you can name your states whatever you want!

    How do I know which names to choose?

    As I develop my apps, how do I know which VisualStates are available?

    • Completely custom controls: as above, if you are writing both the VisualStateManager and the calls to VisualStateManager.GoToState, name the VisualStates whatever you want! If you define a state named State1, you can activate it in codebehind with GoToState State1.
    • Custom templates for existing controls: if you are retemplating an existing control (using ControlTemplate), you should choose names that match the existing states on that control. For example, Button defines CommonStates: Hovered, PointerOver, Pressed, and Disabled. Define those. States with other names will not ever be activated (since the codebehind written by the XAML team doesn't ever GoToState with that name). To know the existing states—

    How do I know the existing VisualStates of a control?

    1. Look up the default ControlTemplate (or Style with TargetType of your desired type) for your control (which, as mentioned earlier, you can find in the XAML designer or in generic.xaml).
    2. Use the names in the template's VisualStateGroup.

    Wrong name?

    What happens if I use the wrong names?

    Since the names are arbitrary, "wrong name" is not the clearest question here. It's easier to look at two cases:

    • You define a VisualState that codebehind never activates with GoToState (e.g. you added a state called CitelaosGreatState or Hover to your custom template for a Button): nothing awful happens, but your state will never be activated.
    • You fail to define a VisualState that codebehind tries to activate (e.g. you added an incomplete VisualStateGroup for your custom Button template): the GoToState call has no effect.