Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding duplication in WPF (following DRY)

Tags:

wpf

dry

Consider the follow 2 XAML snippets (which are side-by-side in the file):

<Button
    x:Name="BuyButton"
    Margin="0,0,1,1"
    IsEnabled="{Binding CanBuy}"
    >
    <StackPanel
        DataContext="{Binding Product}">
        <TextBlock
            Foreground="Red"
            Text="BUY" />
        <TextBlock
            Foreground="Red"
            Text="{Binding BuyPrice}" />
    </StackPanel>
    </Button>

<Button
    x:Name="SellButton"
    Margin="0,0,1,1"
    IsEnabled="{Binding CanSell}"
    >
    <StackPanel
        DataContext="{Binding Product}">
        <TextBlock
            Foreground="Red"
            Text="SELL" />
        <TextBlock
            Foreground="Red"
            Text="{Binding SellPrice}" />
    </StackPanel>
</Button>

How does one remove duplication in WPF? I have approx 4 uses (2 shown here) of this type of button, and they're 80% the same, if not more. I could extract this into a user control and put a few DPs on it and then I'd have one control, but I fear that I will start littering my code base with tons of user controls (I have a lot of "one-off" situations like this). I don't like the DataTemplate solution here because I'd still need two templates, which would have repeated code. Without creating a bunch of templates/controls, is there a way of making this code follow DRY?

like image 282
DavidN Avatar asked Mar 09 '09 20:03

DavidN


1 Answers

A ControlTemplate might work:

<ControlTemplate x:Key="ButtonControlTemplate1" TargetType="{x:Type Button}">
<StackPanel Height="Auto" Width="Auto">
    <TextBlock Text="{TemplateBinding Content}" Foreground="Red"/>
    <TextBlock Text="{TemplateBinding Tag}" Foreground="Red"/>
</StackPanel></ControlTemplate>  

I used TemplateBinding to get the two changeable pieces of data. Now when you create the button, apply the Template, and set the Bindings to your elements:

<Button x:Name="BuyButton"
    Margin="0,0,1,1"
    IsEnabled="{Binding CanBuy}"
    Template="{DynamicResource ButtonControlTemplate1}"
    Content="Button" 
    Tag="{Binding BuyPrice}"/>

The only thing missing is the DataContext: just set it at a container above the two buttons.

I haven't tried it specifically, but it seems it should work. I chose "Tag" above because I needed a second element for Binding. I'd love to see different suggestions about this.

You probably also want to break the ForegroundColor="Red" type stuff into a style.

like image 200
Joel Cochran Avatar answered Sep 23 '22 20:09

Joel Cochran