Let us consider an implementation of a described above
approach based on a Button control template creation. First, it is necessary to
redefine a control element template. It can be done in a style or directly with
help of a property setting. We will define a template through the direct
setting of a Template property.
Listing 1 - Simple button definition
<Button Content="Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid />
</ControlTemplate>
</Button.Template>
</Button>
As a result of this definition, we get an empty button. So
it is necessary to fill it with content.
Listing 2 - Simple button definition with contents
<Button Content="Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Border CornerRadius="3" BorderBrush="Black" BorderThickness="1"
Background="Silver" />
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Thanks to this definition the button has gotten borders and
begun to display its content. However, in the given template there is no
dynamics. If we hover the mouse cursor to the button or press it, nothing will
change. It is easy to be changed. For example, in the simplest case it is
possible to change a button background. For that end, if adding some control
elements, it will be displayed in various states.
Listing 3 - The button definition with contents and
additional layout
<Button Content="Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<Border Name="NormalBackground" CornerRadius="3"
BorderBrush="Black" BorderThickness="1" Background="Silver" />
<Border Name="HoverBackground" Opacity="0"
CornerRadius="3" BorderBrush="Black" BorderThickness="3" Background="Gray" />
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
Pay attention to the fact "HoverBackground"
control element is hidden in this case (property Opacity equals 0). Our goal is
to display it at the moment of the mouse cursor hovering over the button and to
hide in the opposite situation. For this purpose it is necessary to define
VisualStateManager object which will execute all work.
Listing 4 - The button definition with VisualStateManager
<Button Content="Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation To="1"
Duration="0:00:00.5" Storyboard.TargetName="NormalBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="HoverBackground" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="NormalBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="1"
Duration="0:00:00.5" Storyboard.TargetName="HoverBackground" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Name="NormalBackground" CornerRadius="3"
BorderBrush="Black" BorderThickness="1" Background="Silver" />
<Border Name="HoverBackground" Opacity="0"
CornerRadius="3" BorderBrush="Black" BorderThickness="3" Background="Gray" />
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
There is a similar way to manage a control element
appearance for several states. For example, it is possible to add to the button
a representation of state "pressed."
Listing 5 - The button definition with
VisualStateManager which describes three states
<Button Content="Button">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation To="1"
Duration="0:00:00.5" Storyboard.TargetName="NormalBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="HoverBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="PressedBackground" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="NormalBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="1" Duration="0:00:00.5"
Storyboard.TargetName="HoverBackground"
Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="PressedBackground"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="NormalBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0"
Duration="0:00:00.5" Storyboard.TargetName="HoverBackground" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="1"
Duration="0:00:00.5" Storyboard.TargetName="PressedBackground"
Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Name="NormalBackground" CornerRadius="3"
BorderBrush="Black" BorderThickness="1" Background="Silver" />
<Border Name="HoverBackground" Opacity="0"
CornerRadius="3" BorderBrush="Black" BorderThickness="3" Background="Gray" />
<Border Name="PressedBackground" Opacity="0"
CornerRadius="8" BorderBrush="Black" BorderThickness="1" Background="Red" />
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
As a result, the given button will look differently in three
various states - normal, pressed and hovered.