WPF Killed the RadioButton Star
Ok, it’s a really dumb title for a blog post, but this is just a little love for WPF and its ability to completely restyle a standard control.
In our most recent project, we have a list of groups of pigs that we show the user so they can choose one to work with. The groups might be male, female, castrates or mixed, and we need to let the user filter the list by sex so that there’s not as many to choose from.
We ended up using RadioButtons, one for each sex. As an example, here’s the XAML for the “Females” option:
<RadioButton Grid.Column="2" Tag="{x:Static qfp:ProgenySex.Female}" ToolTip="Show only female groups"> <Label>_Females</Label> </RadioButton>
However, we knew that the filtering options in the finished product shouldn’t look like radio buttons. In fact, the effect I wanted was closer to the FlatButtons appearance on the TabControl in Windows Forms:
In the end, with a little bit of XAML templating, I was able to achieve exactly the look I wanted. It’s even better than the TabControl! Here’s a screenshot:
So the “buttons” at the top of the list are actually RadioButtons (using the XAML above), and in this screenshot the user has selected “Females”. Below is a part of the XAML we used to restyle the radio buttons (I’ve omitted the icon setters etc). It just goes to show how powerful WPF is!
<Style TargetType="{x:Type RadioButton}"> <EventSetter Event="ToggleButton.Checked" Handler="SetProgenySexFilter" /> <Setter Property="Focusable" Value="False" /> <Setter Property="GroupName" Value="filter"/> <Setter Property="IsTabStop" Value="False" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type RadioButton}"> <ControlTemplate.Resources> <Style TargetType="{x:Type Image}"> <Setter Property="Height" Value="16" /> <Setter Property="Width" Value="16" /> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="Margin" Value="0,0,2,0" /> </Style> <Style TargetType="{x:Type TextBlock}"> <Setter Property="VerticalAlignment" Value="Center"/> </Style> <Style TargetType="{x:Type Label}"> <Setter Property="Padding" Value="0"/> </Style> </ControlTemplate.Resources> <Border x:Name="PART_border" CornerRadius="2" Padding="3px" Margin="2px" Background="Transparent" BorderThickness="1" BorderBrush="{x:Static SystemColors.ControlDarkBrush}" SnapsToDevicePixels="True"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Image x:Name="PART_icon" /> <ContentPresenter x:Name="PART_content" /> </StackPanel> </Border> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="PART_content" Property="TextBlock.FontWeight" Value="Bold"/> <Setter TargetName="PART_border" Property="Background"> <Setter.Value> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="{x:Static SystemColors.ControlLightColor}"
Offset="0"/> <GradientStop Color="{x:Static SystemColors.ControlColor}"
Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> </Trigger>

Comments
# sa
15/10/2009 9:41 AM
I cannot get this work. Could you please be more specific? How do you set the image and how do you set the text.
# mabster
15/10/2009 9:49 AM
Hi sa,
You're right - there's an extra style trigger in there where I set the image depending on the actual sex represented by the radio button's tag. It's very specific to our program, though, and outside the scope of this post, so I didn't bother including it.
It's along the lines of:
<Trigger Property="Tag" Value="{x:Static qfp:ProgenySex.Male}"> <Setter TargetName="PART_icon" Property="Source" Value="/Resources/male.png" /> </Trigger># Kory
22/10/2009 10:10 AM
Found your site, and inspired from it, and thought I would leave a comment...
Instead of using a trigger to set the icon, you could use something like this:
<Rectangle x:Name="PART_icon" Fill="{TemplateBinding Background}" />
Then, when you use the radio button you can spcify the image to use like:
<RadioButton Tag="item 4" Background="{DynamicResource MyImageBrush}">
by using the Background property.
My resource is in a dll, and declared like:
<ImageBrush x:Key="MyImageBrush" ImageSource="/path/to/image.jpg" />
Kory
# mabster
22/10/2009 10:14 AM
That's true, Kory - we could define the image on the radiobuttons themselves (using your background idea). I do like the idea, though, of the radiobuttons being fairly "dumb" and only binding their tags to the sex, letting the template decide which image to render.
Thanks for your comment!
Leave a Comment