Click here to Skip to main content
15,885,278 members
Articles / Desktop Programming / WPF
Tip/Trick

Passing Custom-Properties into Styled/Templated Control with triggers

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
30 Aug 2013CPOL1 min read 14.7K   145   1  
Simple way to pass custom(Attached) properties into a style-based control-template with triggers

 Image 1

Introduction

A few days ago, one of my colleagues came to me with a question - 'What is the easiest way to pass special properties into a templated control with triggers?' Later he came back with a solution he found on the internet, once saw it, I thought I could do better... 

Background 

For my test app I've choose to template a Button-Control in the well know pattern consist of a style with a template setter.

The Button will be Templated into an ellipse shaped Button, with the content (text). This content will be colored depending on Mouse-Over state. 

Using the code 

As it is implied from the test-app description we will need two special properties:

  1. Content(text)- Brush while Mouse-Over.
  2. Content(text)- Brush while Mouse-Not-Over. 

In WPF the term 'special'/'additional' properties usually directly translates to  'Attached-Properties'. So, I've added two of the matching types to my project (located inside the MainWindow's code-behind partial class , for simplicity. 

C#
public static SolidColorBrush  GetMouseOverBrush(DependencyObject obj)
{
    return (SolidColorBrush )obj.GetValue(MouseOverBrushProperty);
}

public static void SetMouseOverBrush(DependencyObject obj, SolidColorBrush  value)
{
    obj.SetValue(MouseOverBrushProperty, value);
}

// Using a DependencyProperty as the backing store for MouseOverBrush.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty MouseOverBrushProperty =
    DependencyProperty.RegisterAttached("MouseOverBrush", 
    typeof(SolidColorBrush ), typeof(MainWindow), new PropertyMetadata(new SolidColorBrush(Colors.Green)));

public static SolidColorBrush  GetNotMouseOverBrush(DependencyObject obj)
{
    return (SolidColorBrush )obj.GetValue(NotMouseOverBrushProperty);
}

public static void SetNotMouseOverBrush(DependencyObject obj, SolidColorBrush  value)
{
    obj.SetValue(NotMouseOverBrushProperty, value);
}

// Using a DependencyProperty as the backing store for NotMouseOverBrush.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty NotMouseOverBrushProperty =
    DependencyProperty.RegisterAttached("NotMouseOverBrush", typeof(SolidColorBrush ), 
    typeof(MainWindow), new PropertyMetadata(new SolidColorBrush(Colors.LightBlue)));

These properties values can be set in three different layers:

  1. At the Attached-Property default value - as the property 'basic' default value (as seen above).
  2. At the style-level setters- acting as the Style's default value for these properties (as seen in derived style code).
  3. At the actual implementation of the style (styled-button on this case (second button))

After declaring those properties, the template (inside the style's 'template' property-setter), can use these properties in the following manner:

XML
<Style x:Key="MyButtonStyle" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value> 
            <ControlTemplate TargetType="Button">
                <Grid >
                    <Ellipse x:Name="ell"  Fill="Gray" Stroke="Red"/>
                    <ContentPresenter  x:Name="tb"  Content ="{TemplateBinding Content}" 
                      HorizontalAlignment="Center" VerticalAlignment="Center" 
                      TextElement.Foreground="{TemplateBinding  app:MainWindow.NotMouseOverBrush}" 
                      IsHitTestVisible="False"/>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger SourceName="ell" Property="IsMouseOver" Value="True">
                        <Setter Property="TextElement.Foreground" 
                          TargetName="tb" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                          Path=(app:MainWindow.MouseOverBrush)}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And derived(based-on) styles can change them like this:

XML
<Style x:Key="MySecondButtonStyle" BasedOn="{StaticResource MyButtonStyle}" TargetType="Button">
    <Setter Property="app:MainWindow.MouseOverBrush" Value="LightGreen"/>
    <Setter Property="app:MainWindow.NotMouseOverBrush" Value="Gold"/>
</Style>

Last, the Styled-Button implementation: 

XML
<Button Grid.Row="0" Content="My Button Style" Style="{StaticResource MyButtonStyle}" />
<Button Grid.Row="1" Content="My Button Style Modified" Style="{StaticResource MyButtonStyle}" 
   app:MainWindow.MouseOverBrush="Yellow" app:MainWindow.NotMouseOverBrush="Pink"/>
<Button Grid.Row="2" Content="My second Button Style" Style="{StaticResource MySecondButtonStyle}"  />

That's it. hope You've found it useful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) self employed
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --