100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
.NET

Visual States in XAML

How VisualStateManager, VisualStateGroups, and VisualState define named, animated appearance changes for a control, and how GoToState transitions between them.

Layout and ControlsIntermediate9 min readJul 10, 2026
Analogies

Why Visual States Exist

Visual states let a control's ControlTemplate declare named appearance variations — like Normal, MouseOver, Pressed, or Disabled — directly in XAML instead of scattering Storyboard triggers across code-behind. VisualStateManager.VisualStateGroups is attached to the template's root element and groups related, mutually exclusive states together, such as a CommonStates group holding Normal/MouseOver/Pressed/Disabled.

🏏

Cricket analogy: VisualStateGroups are like a match officials' rulebook naming discrete states — Play, Drinks Break, Rain Delay — declared once in the regulations rather than umpires improvising ad hoc calls, so every ground follows the same named states.

VisualStateGroups and Mutually Exclusive States

Within a single VisualStateGroup, only one VisualState can be active at a time — a button can't be simultaneously Normal and Pressed — but a control can have several independent groups active simultaneously, such as CommonStates and FocusStates changing different visual properties at once. Each VisualState contains a Storyboard that animates specific properties (like Background or Opacity) on named elements inside the template.

🏏

Cricket analogy: A single VisualStateGroup enforces exclusivity like an umpire's decision — a batsman is either Out or Not Out, never both — while a separate independent group like weather conditions (Sunny/Overcast) can change at the same time without conflicting.

Transitioning with GoToState

Control authors call VisualStateManager.GoToState(control, "MouseOver", true) from code, typically inside overridden OnMouseEnter/OnMouseLeave handlers, to request a transition into a named state; the boolean parameter controls whether the transition should animate or snap instantly. VisualTransition elements let you customize the animation duration and easing used when moving from one specific state to another, rather than relying on a single default transition for every state change.

🏏

Cricket analogy: Calling GoToState from OnMouseEnter is like a twelfth man sprinting onto the field the instant a fielder signals injury — the transition is triggered by a specific event, and how fast it happens can be tuned like a VisualTransition's duration.

Visual States vs. Triggers

Compared to older Trigger/DataTrigger-based styling, visual states centralize all of a control's appearance logic into one place per state, making a custom ControlTemplate easier to reason about, and they compose better with the built-in states that ItemsControl-derived and ButtonBase-derived controls already expect. However, because states are typically driven from a control's own code (not purely from data bindings), fully custom controls need a corresponding C# partial class that calls GoToState at the right lifecycle moments.

🏏

Cricket analogy: Centralizing appearance logic per visual state is like keeping every rule for a rain-delay procedure in one page of the playing conditions document, rather than scattering related clauses for the same delay across several separate rulebook sections.

xml
<ControlTemplate TargetType="Button">
    <Border x:Name="Bg" Background="#3A6EA5" CornerRadius="4">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="Bg"
                            Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                            To="#4C8BC9" Duration="0:0:0.15"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Pressed">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="Bg"
                            Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                            To="#2C5580" Duration="0:0:0.05"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Disabled">
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="Bg" Storyboard.TargetProperty="Opacity" To="0.4" Duration="0"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Border>
</ControlTemplate>

Always include an empty Normal VisualState (even with no Storyboard) in every VisualStateGroup — it gives GoToState a defined baseline to animate back to when leaving MouseOver, Pressed, or Disabled, instead of leaving the control stuck at its last animated values.

A Storyboard inside a VisualState that targets a name via Storyboard.TargetName silently does nothing if no element with that x:Name exists in the current template — there's no compile error, the state transition simply has no visible effect, which makes typos in TargetName a common source of 'my hover state isn't working' bugs.

  • VisualStateManager.VisualStateGroups on a template's root element groups related, mutually exclusive states.
  • Only one VisualState within a given VisualStateGroup can be active at a time.
  • Multiple independent VisualStateGroups (e.g., CommonStates and FocusStates) can be active simultaneously.
  • Each VisualState contains a Storyboard animating specific properties on named template elements.
  • VisualStateManager.GoToState(control, stateName, useTransitions) requests a transition into a named state.
  • VisualTransition elements customize the duration/easing used between specific state pairs.
  • Visual states centralize a control's appearance logic per state instead of scattering trigger-based rules.

Practice what you learned

Was this page helpful?

Topics covered

#NET#XAMLStudyNotes#MicrosoftTechnologies#VisualStatesInXAML#Visual#States#XAML#Exist#StudyNotes#SkillVeris