Skip Navigation LinksHome > View Post

My dirty little secret from Reason 3. ControlTemplates

Earlier I introduced a series of posts entitled 10 reasons to consider WPF for your next desktop application. If you haven't read the intro yet, better head on back and read it first.

WPF's ControlTemplates didn't make my 10 reasons you should consider WPF for your next desktop application but it was close. Perhaps they should have.

I feel like I'm keeping a dirty little secret from you and I can't do it anymore. In Reason 3. we took a look at DataTemplates and inside the DataTemplate we created a little 'bar' to show the CustomerRating for each of the books:

This was created using the following Xaml inside our DataTemplate

<Border BorderBrush="Black" BorderThickness="1" Width="100" Height="20" Background="White"
                    SnapsToDevicePixels="True" HorizontalAlignment="Left">
    <Viewbox Stretch="Fill">
        <Border Width="5" BorderThickness="0">
            <Rectangle Width="{Binding CustomerRating}" Fill="Orange"
                                 Height="10" HorizontalAlignment="Left"/>
        </Border>
    </Viewbox>
</Border>

Note that the Rectangle's Width property is bound to our Customer Rating. Because this varies from 0 to 5 we put it inside a Border that is fixed to 5 pixels (or rather, device independent units) and then we put the whole thing in a Viewbox to scale it up.

And this works pretty well but if we look closely at exactly what it is we're trying to do - we'll see that there is already a control in WPF that is built to do just this. The ProgressBar. Seriously!

ratings in ProgressBars!

This was created using the following Xaml inside our DataTemplate

<ProgressBar Value="{Binding CustomerRating}" Minimum="0" Maximum="5" />

Notice how we specify a minimum (0), a maximum (5) and bind the Value to our CustomerRating.

The only problem is we don't want to use ProgressBars that actually look like ProgressBars!

Guess what? as with most things in WPF: "where there's a want there's a way"

ControlTemplates

Yup, we can reskin the ProgressBar to look how we want it to using a ControlTemplate:

<ControlTemplate x:Key="ratingBarTemplate" TargetType="{x:Type ProgressBar}">
    <Border Name="PART_Track" Width="{TemplateBinding Width}" BorderBrush="Black" BorderThickness="1" SnapsToDevicePixels="True">
        <Rectangle Name="PART_Indicator" HorizontalAlignment="Left" Fill="Orange" Height="{TemplateBinding Height}" />
    </Border>
</ControlTemplate>

Note that this has an x:Key attribute - that's because we're using it as a resource. I've talked about Resources in Xaml before here: Xaml. Using Resources. Don't worry, it's easy.

Now we apply this to our ProgressBar (inside our DataTemplate) like so:

<ProgressBar Template="{StaticResource ratingBarTemplate}" ...

And hey presto!

ratings in ProgressBars that look how we want them to!

Extending the ProgressBar

I'm not entirely happy yet. I want to be able to change the Fill colour of our orange rectangle on the ProgressBar object itself, something like this:

<ProgressBar Fill="Orange" ...

But since the ProgressBar has no such property this isn't possible. It's easily solved though, we can simply inherit from ProgressBar to create our own RatingBar control.

public class RatingBar : ProgressBar
{
    public static DependencyProperty FillProperty =
        DependencyProperty.Register("Fill",
            typeof(Brush),
            typeof(RatingBar),
            new FrameworkPropertyMetadata(
                Brushes.Orange,
                FrameworkPropertyMetadataOptions.AffectsRender));

    public Brush Fill
    {
        get
        {
            return (Brush) GetValue(FillProperty);
        }
        set
        {
            SetValue(FillProperty, value); }
        }
    }
}

Now we just need to add another TemplateBinding to our rectangle inside the control template

<Rectangle Name="PART_Indicator" HorizontalAlignment="Left" Fill="{TemplateBinding Fill}" Height="{TemplateBinding Height}" />

To finish, we just use the RatingBar instead of the ProgressBar.

Bingo.

As promised, I will be releasing the source for the examples for all 10 reasons at the end of the series. The source and example in Reason4 includes this stuff as it builds on the pieces in Reason3.

Tags: WPF

 
Josh Post By Josh Twist
4:01 AM
19 Oct 2007

» Next Post: Reason 4. Triggers
« Previous Post: Reason 3. DataTemplates

Comments are closed for this post.

Posted by Josh @ 19 Oct 2007 4:05 AM
Forgot to mention, Charles Petzold has a great article that was published in MSDN magazine on Control Templates here: http://msdn.microsoft.com/msdnmag/issues/07/01/Foundations/default.aspx

© 2005 - 2014 Josh Twist - All Rights Reserved.