Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameterized style/template in WPF?

Tags:

wpf

If I have two 200 lines long control templates which differ only in a few words (a few colors), how can I make the xaml reusable ? That is, to don't have to copy-paste the template and change 3 words in 200 lines.

Here is a simplified example. The only difference between the two styles is the border color. So can I somehow define a ButtonStyle, with a parameterized color, and inherit BlackButtonStyle and GrayButtonStyle from it, and specify only that color in BlackButtonStyle and GrayButtonStyle ?

alt text

<Window x:Class="WpfApplication33.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>

        <Style x:Key="BlackButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border BorderBrush="Black" BorderThickness="3">
                            <ContentControl Content="{TemplateBinding Content}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Key="GrayButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border BorderBrush="Gray" BorderThickness="3">
                            <ContentControl Content="{TemplateBinding Content}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>
    <StackPanel>
        <Button Content="Black Button"
                Style="{StaticResource BlackButtonStyle}"/>
        <Button Content="Gray Button"
                Style="{StaticResource GrayButtonStyle}"/>
    </StackPanel>
</Window>

Here is the code based on the 2 answers. Only a style needs to be set on the control, but unfortunately it still messes up the Tag of the control:

<Window x:Class="WpfApplication33.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>

        <Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Name="border"
                                BorderBrush="Black"
                                BorderThickness="3">
                            <ContentControl Content="{TemplateBinding Content}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="Tag" Value="Gray">
                                <Setter TargetName="border"
                                        Property="BorderBrush"
                                        Value="Gray"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Key="BlackButtonStyle"
               TargetType="{x:Type Button}"
               BasedOn="{StaticResource ButtonStyle}"/>
        <Style x:Key="GrayButtonStyle"
               TargetType="{x:Type Button}"
               BasedOn="{StaticResource ButtonStyle}">
            <Setter Property="Tag" Value="Gray"/>
        </Style>

    </Window.Resources>
    <StackPanel>
        <Button Content="Black Button"
                Style="{StaticResource BlackButtonStyle}"/>
        <Button Content="Gray Button"
                Style="{StaticResource GrayButtonStyle}"/>
    </StackPanel>
</Window>
like image 826
Jeno Csupor Avatar asked Aug 06 '10 16:08

Jeno Csupor


3 Answers

While Charlie's right about his example, for your specific case I'd just use the BorderThickness and BorderBrush properties that a button already exposes: you can use {TemplateBinding BorderBrush} instead of creating your own property.

Edit: sample xaml... note that my style defaults the color & thickness, but these could be overridden inline...

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1" Height="300" Width="300">
<Page.Resources>
    <SolidColorBrush x:Key="BlackBrush" Color="Black"/>
    <SolidColorBrush x:Key="GrayBrush" Color="Gray"/>
    <Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="BorderThickness" Value="3" />
        <Setter Property="BorderBrush" Value="{StaticResource BlackBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderColor="{TemplateBinding BorderThickness}">
                        <ContentControl Content="{TemplateBinding Content}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<StackPanel>
    <Button Content="Black Button" BorderBrush="{StaticResource BlackBrush}"
            Style="{StaticResource CustomButtonStyle}"/>
    <Button Content="Gray Button" BorderBrush="{StaticResource GrayBrush}"
            Style="{StaticResource CustomButtonStyle}"/>
</StackPanel>
like image 135
Dan Puzey Avatar answered Nov 04 '22 21:11

Dan Puzey


The right way to go about this is usually to create a DependencyProperty on the class that can hold the parametrized data, and then bind to that property in your template. For the sake of creating a quick example, I'm going to use the Button.Tag property, which works perfectly well for storing something as simple as a brush:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1" Height="300" Width="300">
<Page.Resources>
    <SolidColorBrush x:Key="BlackBrush" Color="Black"/>
    <SolidColorBrush x:Key="GrayBrush" Color="Gray"/>
    <Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border BorderBrush="{TemplateBinding Tag}" BorderThickness="3">
                        <ContentControl Content="{TemplateBinding Content}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

<StackPanel>
    <Button Content="Black Button" Tag="{StaticResource BlackBrush}"
            Style="{StaticResource CustomButtonStyle}"/>
    <Button Content="Gray Button" Tag="{StaticResource GrayBrush}"
            Style="{StaticResource CustomButtonStyle}"/>
</StackPanel>

like image 35
Charlie Avatar answered Nov 04 '22 20:11

Charlie


Have a look at this solution, it solves the exact issue you're having.

like image 3
Thomas Levesque Avatar answered Nov 04 '22 21:11

Thomas Levesque