All standard control elements have a set of predetermined states.
These conditions can be used developing a new control element template. The
same approach can be used to create your own control elements. Let us create a
new one and add a text property to it.
Listing 6 - The definition of new control
public class SampleControl : Control
{
public static readonly DependencyProperty SomeTextProperty =
DependencyProperty.Register("SomeText", typeof(string),
typeof(SampleControl), null);
public string SomeText
{
get
{
return GetValue(TemplateProperty) as string;
}
set
{
SetValue(TemplateProperty, value);
}
}
}
Now it is necessary to define time moments when the control
element will switch its state. It can be an event of receiving HTTP-request
response, switching an internal element state, etc. In our case we simplify the
example. We create some methods which simulate state switching.
Listing 7 - The definition of new control with
switching methods
public class SampleControl : Control
{
public static readonly DependencyProperty SomeTextProperty =
DependencyProperty.Register("SomeText", typeof(string),
typeof(SampleControl), null);
public string SomeText
{
get
{
return GetValue(TemplateProperty) as string;
}
set
{
SetValue(TemplateProperty, value);
}
}
public void DoSomething()
{
VisualStateManager.GoToState(this, "State1", true);
}
public void DoSomethingElse()
{
VisualStateManager.GoToState(this, "State2", true);
}
public void Clear()
{
VisualStateManager.GoToState(this, "Normal", true);
}
}
It is necessary to add a description of states for our
control element, marking with a special attribute TemplateVisualStateAttribute
should be used.
Listing 8 - The describing of states for the
control
[TemplateVisualState(GroupName = "CommonStates", Name = "Normal")]
[TemplateVisualState(GroupName = "CommonStates", Name = "State1")]
[TemplateVisualState(GroupName = "CommonStates", Name = "State2")]
public class SampleControl : Control
{
public static readonly DependencyProperty SomeTextProperty =
DependencyProperty.Register("SomeText", typeof(string),
typeof(SampleControl), null);
public string SomeText
{
get
{
return GetValue(TemplateProperty) as string;
}
set
{
SetValue(TemplateProperty, value);
}
}
public void DoSomething()
{
VisualStateManager.GoToState(this, "State1", true);
}
public void DoSomethingElse()
{
VisualStateManager.GoToState(this, "State2", true);
}
public void Clear()
{
VisualStateManager.GoToState(this, "Normal", true);
}
}
After that a control element template should be defined. Usage
of VisualStateManager object will help to define a representation for each
state. As an example we will display a text field with a name of the current
state. Besides, in a state "Normal" we will display the text from "SomeText"
property. In this case the following template should be defined to the control
element.
Listing 9 - The describing of states for the
control
<myapp:SampleControl x:Name="MyControl1">
<myapp:SampleControl.Template>
<ControlTemplate TargetType="myapp:SampleControl">
<Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation To="1" Duration="0:00:00.5"
Storyboard.TargetName="NormalText" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="State1Text" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="State2Text" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="State1">
<Storyboard>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="NormalText" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="1" Duration="0:00:00.5"
Storyboard.TargetName="State1Text" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="State2Text" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="State2">
<Storyboard>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="NormalText" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="0" Duration="0:00:00.5"
Storyboard.TargetName="State1Text" Storyboard.TargetProperty="Opacity"/>
<DoubleAnimation To="1" Duration="0:00:00.5"
Storyboard.TargetName="State2Text" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<TextBlock x:Name="NormalText" Text="{TemplateBinding SomeText}"/>
<TextBlock x:Name="State1Text" Text="State1" Opacity="0"/>
<TextBlock x:Name="State2Text" Text="State2" Opacity="0"/>
</Grid>
</ControlTemplate>
</myapp:SampleControl.Template>
</myapp:SampleControl>
Now if the object methods are called externally, the state
changes. Changing a control element state is the reason of its appearance
modification.