Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template Binding with Attached Properties

I have a standard style for my buttons but I want certain parts of the style to be configurable. e.g. I have a border appear when MouseOver is triggered for the button and I want the border colour to be configurable.

Following this article: http://www.thomaslevesque.com/2011/10/01/wpf-creating-parameterized-styles-with-attached-properties/ I thought I could use attached properties and TemplateBinding to achieve this.

I created the following attached property:

public static class ThemeProperties {     public static Brush GetButtonBorderColour(DependencyObject obj)     {         return (Brush)obj.GetValue(ButtonBorderColourProperty);     }      public static void SetButtonBorderColour(DependencyObject obj, Brush value)     {         obj.SetValue(ButtonBorderColourProperty, value);     }      public static readonly DependencyProperty ButtonBorderColourProperty =         DependencyProperty.RegisterAttached(             "ButtonBorderColour",             typeof(Brush),             typeof(ThemeProperties),             new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.Inherits)); } 

I set the property like so:

<Button Style="{StaticResource RedButton}" local:ThemeProperties.ButtonBorderColour="#B20000"/> 

And my style looks like this:

<Window.Resources>     <Style x:Key="RedButton" TargetType="Button">         <Setter Property="OverridesDefaultStyle" Value="True"/>         <Setter Property="Margin" Value="2"/>         <Setter Property="FontFamily" Value="Tahoma"/>         <Setter Property="FontSize" Value="11px"/>         <Setter Property="FontWeight" Value="Bold"/>         <Setter Property="Foreground" Value="White"/>         <Setter Property="MinHeight" Value="25" />          <Setter Property="FocusVisualStyle" Value="{StaticResource MyFocusVisual}" />         <Setter Property="Background" >             <Setter.Value>                 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >                     <GradientStop Color="#FECCBF" Offset="0.2"/>                     <GradientStop Color="Red" Offset="0.85"/>                     <GradientStop Color="#FECCBF" Offset="1"/>                 </LinearGradientBrush>             </Setter.Value>         </Setter>         <Setter Property="Template">             <Setter.Value>                 <ControlTemplate TargetType="Button">                     <Border Name="border" BorderThickness="1" Padding="4,2" BorderBrush="Transparent" CornerRadius="3" Background="{TemplateBinding Background}">                         <Grid >                             <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>                         </Grid>                     </Border>                     <ControlTemplate.Triggers>                         <Trigger Property="IsMouseOver" Value="True">                             <Setter TargetName="border" Property="BorderBrush" Value="{TemplateBinding local:ThemeProperties.ButtonBorderColour}" />                             <Setter Property="Foreground" Value="#B20000" />                         </Trigger>                         <Trigger Property="IsPressed" Value="True">                             <Setter Property="Background" >                                 <Setter.Value>                                     <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >                                         <GradientStop Color="#FECCBF" Offset="0.35"/>                                         <GradientStop Color="Red" Offset="0.95"/>                                         <GradientStop Color="#FECCBF" Offset="1"/>                                     </LinearGradientBrush>                                 </Setter.Value>                             </Setter>                             <Setter TargetName="content" Property="RenderTransform" >                                 <Setter.Value>                                     <TranslateTransform Y="1.0" />                                 </Setter.Value>                             </Setter>                         </Trigger>                         <Trigger Property="IsDefaulted" Value="True">                             <Setter TargetName="border" Property="BorderBrush" Value="#B20000" />                         </Trigger>                         <Trigger Property="IsFocused" Value="True">                             <Setter TargetName="border" Property="BorderBrush" Value="#B20000" />                         </Trigger>                         <Trigger Property="IsEnabled" Value="False">                             <Setter TargetName="border" Property="Opacity" Value="0.7" />                             <Setter Property="Foreground" Value="Gray" />                         </Trigger>                     </ControlTemplate.Triggers>                 </ControlTemplate>             </Setter.Value>         </Setter>     </Style> </Window.Resources> 

Where the key line is

<Trigger Property="IsMouseOver" Value="True">     <Setter TargetName="border" Property="BorderBrush" Value="{TemplateBinding local:ThemeProperties.ButtonBorderColour}" />     <Setter Property="Foreground" Value="#B20000" /> </Trigger> 

As far as I can see this should work but I get the following error during runtime on the above line:

Cannot convert the value in attribute 'Value' to object of type ''. Error at object 'System.Windows.Setter' in markup file

Have I done something incorrect here? I'm brand new to WPF and can't figure what's going wrong as the Type of the attached property is a Brush which is what I would expect the BorderBrush property of a Border to want.

like image 659
thudbutt Avatar asked Feb 10 '12 17:02

thudbutt


People also ask

What is attached dependency property?

Attached properties are a special kind of DependencyProperties. They allow you to attach a value to an object that does not know anything about this value. A good example for this concept are layout panels. Each layout panel needs different data to align its child elements.

How do I use template binding?

To modify the visual tree generated by a template to reflect the control's property values, you must use template bindings. A template binding is a special type of data binding that allows you to reference the parent control, read its properties and apply their values. In some cases, you can use the values directly.


1 Answers

I think TemplateBinding is evaluated at compile time so you can't dynamically set a TemplateBinding in your Setter, try using Binding instead (see below).

<Setter TargetName="border" Property="BorderBrush"          Value="{Binding Path=(local:ThemeProperties.ButtonBorderColour),                         RelativeSource={RelativeSource TemplatedParent}}"/> 

Hope this helps.

like image 190
XiaoChuan Yu Avatar answered Oct 04 '22 17:10

XiaoChuan Yu