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:
# 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!
# Regular User
18/11/2010 7:19 AM
This is the worst example on the web - it shows you something you want to do but absolutely is totally fucking incomplete. Way to go half way on this post buddy!
Please omit a few more lines of code to make it more difficult to cut and paste.
# TimothyP
18/11/2010 7:38 AM
@SoCalledRegular user... where are you examples m8? @Mambster, keep up the good work!
# shril
29/03/2011 3:47 AM
Well although Regular User was a bit rude it is true that only half an example was posted... just saying.
# lg
16/08/2011 3:13 AM
just arrived and what I see...half of the example.@mabster, please at least write the full example or provide a zip with the source code. it would be helpful for a lot of people!!
# the boxx
7/03/2012 11:24 PM
go figure it out yourslf lg...
sheesh what a lazy bastard
you probably cheat on your exams too