How to use a Dependency Property in a XAML Style
In this post I will demonstrate how to create a dependency property and then use that property in a XAML style.
I have found samples on the internet for each, but not a comprehensive example for both. Hopefully putting these pieces all together for you will save you some time!
First we must declare the dependency property. It must be an attached dependency property to be used in xaml. In this sample I am going to create a button that has a new property called HasPlayButton and another property called HasStopButton to display or hide a path on a checkbox control. This sample will work for Silverlight, Windows Store Apps, Windows Phone Apps and WPF apps, pretty much anything that uses XAML.
First we'll make our new Checkbox control. This is just a simple control that inherits from the Checkbox control. I will be adding two dependency properties to this class:
partial class AppButtton : Checkbox
{
public static readonly DependencyProperty HasPlayButtonProperty = DependencyProperty.RegisterAttached("HasPlayButton", typeof(Visibility), typeof(AdamButton), new PropertyMetadata(Visibility.Visible));
public static void SetHasPlayButton(AdamButton element, Visibility value)
{
element.SetValue(HasPlayButtonProperty, value);
}
public static Visibility GetHasPlayButton(AdamButton element)
{
return (Visibility)element.GetValue(HasPlayButtonProperty);
}
publicVisibility HasPlayButton
{
get { return (Visibility)GetValue(HasPlayButtonProperty); }
set { SetValue(HasPlayButtonProperty, value); }
}
public static readonly DependencyProperty HasStopButtonProperty = DependencyProperty.RegisterAttached("HasStopButton", typeof(Visibility), typeof(AdamButton), new PropertyMetadata(Visibility.Collapsed));
public static void SetHasStopButton(CheckBox element, Visibility value)
{
element.SetValue(HasStopButtonProperty, value);
}
public static Visibility GetHasStopButton(CheckBox element)
{
return (Visibility)element.GetValue(HasStopButtonProperty);
}
public Visibility HasStopButton
{
get { return (Visibility)GetValue(HasStopButtonProperty); }
set { SetValue(HasStopButtonProperty, value); }
}
public AdamButton()
{
InitializeComponent();
}
}
Let's look at the definition of the first dependency property:
public static readonly DependencyProperty HasPlayButtonProperty = DependencyProperty.RegisterAttached("HasPlayButton", typeof(Visibility), typeof(AdamButton), new PropertyMetadata(Visibility.Visible));
You can see that I have defined this as an attached property:
DependencyProperty.RegisterAttached
Next I have to set the type for the value that this property will use. I am using the Visibility type so I can hide my path elements later.
The next parameter is the type that I am setting this property on, which is AdamButton (my custom control).
The last parameter is the default value of this property, which we pass in via the PropertyMetadata class.
new PropertyMetadata(Visibility.Collapsed
Since this is an attached dependency property, we must implement both the Setter and Getter for the property, note, you must use the naming convention followed below:
public static void SetHasPlayButton(AdamButton element, Visibility value)
{
element.SetValue(HasPlayButtonProperty, value);
}
public static Visibility GetHasPlayButton(AdamButton element)
{
return (Visibility)element.GetValue(HasPlayButtonProperty);
}
The last step to complete our custom button is to define the regular normal property on the AdamButton class. This allows our class to be aware of these properties as well.
publicVisibility HasPlayButton
{
get { return (Visibility)GetValue(HasPlayButtonProperty); }
set { SetValue(HasPlayButtonProperty, value); }
}
Our class is now complete and we may use the AdamButton class with the new HasStopButton and HasPlayButton properties any where in xaml.
I am going to create a style for the AdamButton control. This style will implement the new properties we defined above via Template binding in xaml. Before we can use our AdamButton class in xaml, we must first declare it's namespace:
xmlns:a="clr-namespace:PhoneApp2"
Add this to your root node for your application or app.xaml file.
Now we can user our new properties via the AdamButton class in a style. Let's take a look at the Style:
<Style x:Key ="PlayButtonStyleLarge" TargetType="CheckBox">
<Setter Property="Background" Value="#FF448DCA"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="MinWidth" Value="50"/>
<Setter Property="MinHeight" Value="19"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="a:AdamButton">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates" />
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused" />
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}">
<Grid>
<Polygon Points="0,00 50,30, 0,65" Fill="White" Name="StartPoly" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="{TemplateBinding HasPlayButton}" />
<Polygon Points="0,0 50,0, 50,50 0,50" Fill="White" Name="StopPoly" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="{TemplateBinding HasStopButton}"/>
<ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notice the target type for the style is still set to Checkbox, because that is our base class style that xaml (and .net) can recognize:
<Style x:Key ="PlayButtonStyleLarge" TargetType="CheckBox">
However the control template is set to our AdamButton class. This allows me to access my new properties via the control's template binding:
<ControlTemplate TargetType="a:AdamButton">
The "a:" here is our namespace reference we defined earlier.
In my control style I set the visibility of the different paths with our new property:
<Polygon Points="0,00 50,30, 0,65" Fill="White" Name="StartPoly" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="{TemplateBinding HasPlayButton}" />
We now have a button that we can easily style with our new properties in C# code behind. Here's an example of how we can use the AdamButton class:
if ( <value> == true)
{
Button1.HasPlayButton = Visibility.Collapsed;
Button1.HasStopButton = Visibility.Visible;
}
else
{
Button1.HasPlayButton = Visibility.Visible;
Button1.HasStopButton = Visibility.Collapsed;
}
Hope this helps guys!
A
Comments
- Anonymous
October 29, 2015
Thank you! I didn't need to include the getter and setter, it worked without those for me.