As you know, it’s possible to derive one Style from another, in the process inheriting all the Setter objects. The new Style can add to those Setter objects or override them.
However, it is not possible to derive from a ControlTemplate. There’s no way to reference an existing ControlTemplate and specify an additional piece of the visual tree, or a replacement for part of the visual tree. (It’s hard enough imaging the mechanics or syntax of such a process.)
Generally if you want to apply some changes to an existing ControlTemplate, you obtain a copy of that entire template and begin editing
it. These default templates are generally included with Silverlight
documentation. Expression
Blend also has access to the standard default templates.
If you need to share a Style or a ControlTemplate (or a Style containing a ControlTemplate) among multiple controls on a page, you simply put it in the ResourcesStyle or ControlTemplate among multiple pages, put it in the Resources collection of App.xaml. collection of the page. If you need to share the
It is also possible to
share resources among multiple applications. To share these resources
you define them in a XAML file with a root element of ResourceDictionary. Here’s such a file with the name SharedResources.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="brush" Color="Blue" />
. . .
</ResourceDictionary>
The file probably has a lot more resources than just the SolidColorBrush. Each resource has an x:Key
attribute, of course. You could create this file as part of a project,
or you can add this existing file to a project. In either case, the
Build Action in the properties window should indicate Page.
Now you can reference that file in the Resources collection in App.xaml:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="SharedResources.xaml" />
. . .
</ResourceDictionary.MergedDictionaries>
. . .
</ResourceDictionary>
</Application.Resources>
Notice the ResourceDictionary.MergedDictionary property element used for referencing external ResourceDictionary objects.
Here’s a different approach:
You might want to define a custom style and template for an existing
control, and then refer to that control with a new name rather than to explicitly reference the style. That too is possible.
Here’s a program called FlipToggleDemo that includes a custom class named FlipToggleButton that derives from ToggleButton. But FlipToggleButton doesn’t add any code to ToggleButton—just a Style and ControlTemplate.
In the FlipToggleDemo project, I added a new
item of type Windows Phone User Control and I gave it a name of
FlipToggleButton.xaml. This process creates a FlipToggleButton.xaml file
and a FlipToggleButton.xaml.cs file for a class that derives from UserControl. But then I went into both files and changed UserControl to ToggleButton so FlipToggleButton derives from ToggleButton.
To keep things simple, I
decided not to implement any state transitions for a disabled button,
but to flip the button upside down for the Unchecked state. Here’s the
complete XAML file for the custom button, with indentation reduced to 2
spaces to avoid lines wider than the pages of this book:
Example 1. Silverlight Project: FlipToggleDemo File: FlipToggleButton.xaml
<ToggleButton x:Class="FlipToggleDemo.FlipToggleButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ToggleButton.Style> <Style TargetType="ToggleButton"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Border BorderBrush="{StaticResource PhoneForegroundBrush}" BorderThickness="{StaticResource PhoneBorderThickness}" Background="{TemplateBinding Background}" RenderTransformOrigin="0.5 0.5"> <Border.RenderTransform> <RotateTransform x:Name="rotate" /> </Border.RenderTransform>
<VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CheckStates"> <VisualState x:Name="Checked"> <Storyboard> <DoubleAnimation Storyboard.TargetName="rotate" Storyboard.TargetProperty="Angle" To="180" Duration="0:0:0.5" /> </Storyboard> </VisualState>
<VisualState x:Name="Unchecked"> <Storyboard> <DoubleAnimation Storyboard.TargetName="rotate" Storyboard.TargetProperty="Angle" Duration="0:0:0.5" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ToggleButton.Style> </ToggleButton>
|
Usually when you’re looking at XAML file, the bulk of the file is set to the Content property of the root element. Here the bulk of the file is set to the Style property of the root element. Notice that the Style object and the ControlTemplate object both have TargetType set to ToggleButton rather than FlipToggleButton. This is fine because neither references any properties specifically defined by FlipToggleButton because FlipToggleButton does not define any new properties.
The template itself is very plain vanilla, consisting of just a Border and a ContentPresenter with all the standard template bindings. But the Border also has its RenderTransformOrigin property defined and its RenderTransform property set to a RotateTransform object.
The two animations that flip the button upside down (for the Checked
state) and back (for the Unchecked state) have non-zero times. The DoubleAnimation for the Checked state has no From value; it uses the base value of the property, which is zero. The DoubleAnimation for the Unchecked state has neither a To or From value! The animation starts at whatever value the Angle property of the RotateTransform
happens to be—probably 180 but perhaps something lower if the animation
to flip the button hasn’t quite completed when the button is
unchecked—and it ends at the base value, which is zero.
Here’s the complete code-behind file for the custom control:
Example 2. Silverlight Project: FlipToggleDemo File: FlipToggleButton.xaml.cs
using System.Windows.Controls.Primitives;
namespace FlipToggleDemo { public partial class FlipToggleButton : ToggleButton { public FlipToggleButton() { InitializeComponent(); } } }
|
The MainPage.xaml file of the project instantiates the custom button to test it out:
Example 3. Silverlight Project: FlipToggleDemo File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <local:FlipToggleButton Content="Flip Toggle" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid>
|