WPF Data Bound RadioButtonList

|

During the process of writing a WPF application recently, I had the need for a data bound list of items where the options had to be mutually exclusive, so I figured something like a list of RadioButtons would be in order.

However, when I started looking around I could not find a RadioButtonList or anything that fitted the bill out-of-the-box. Therefore, I thought I’d put something together myself; I also needed to have the list render horizontally rather than vertically. This is what I came up with:

<!-- Item Style for the ListBoxItem to add a RadioButton -->
<Style x:Key="RadioButtonItemStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Margin" Value="0,0,5,0" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border BorderThickness="0" Background="Transparent">
                    <!-- Note: IsChecked is bound to IsSelected-->
                    <RadioButton
                        Focusable="False"
                        IsHitTestVisible="False"
                        IsChecked="{TemplateBinding IsSelected}">
                        <ContentPresenter />
                    </RadioButton>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<!-- Turns the ListBox in to a Horizontal ListBox -->
<ItemsPanelTemplate x:Key="HorizontalItemsPanel">
    <VirtualizingStackPanel
        Orientation="Horizontal" />
</ItemsPanelTemplate>

I defined a Style and the ItemsPanelTemplate in the Resources property of my Window that contains all the necessary XAML for the effects I need; note that you could just as easily define this XAML inline on the ListBox as opposed to using the Resources property. I then applied these two new elements to an instance of ListBox using the following mark-up:

<ListBox
    BorderThickness="0"
    ItemsSource="{Binding MyDataList}"
    SelectedValue="{Binding MyDataListSelectedValue}"
    ItemContainerStyle="{StaticResource RadioButtonItemStyle}"
    ItemsPanel="{StaticResource HorizontalItemsPanel}" />
  

I’ve highlighted where I’ve used the two resources.

For this example the data list is trivial and is provided by a ViewModel class attached to the DataContext of the Window; I’m only showing the code here as a example of how you can add sample data to an application, as well as proving that the above XAML all works as expected using a bound list of data:

public class MainWindowViewModel
{
    public IEnumerable<string> MyDataList
    {
        get
        {
            yield return "Stan";
            yield return "Cartman";
            yield return "Kenny";
            yield return "Karl";
        }
    }

    public string MyDataListSelectedValue
    {
        get { return "Cartman"; }
        set { /* TODO: save the value */ }
    }
}

<!-- XAML -->
<Window.DataContext>
    <vm:MainWindowViewModel />
</Window.DataContext>

Here’s what it all looks like in the Visual Studio designer:

image

And there we have it, job done. Hope this helps someone, happy XAML hacking.

4 comments:

Derek Lakin said...

Any ideas when you start to see benefits to using a VirtualizingStackPanel? I'm guessing at such low numbers there isn't really any benefit?

Paul said...

You're absolutely right about the low numbers here; you could simply use a StackPanel. I would also argue that with something like a RadioButtonList you would never really have enough elements to warrant a virtualized panel.

However, as a best practice I would always attempt to keep the template as close to the original control template as possible. There are a number of reasons for this, not least of which is the "special" un-written contracts with some control templates, where the WPF developers have done some optimizations or provided additional behaviour if they find elements of a certain type or find element of a certain type and with a specific name e.g. PART_nnn (ScrollBar, ProgressBar and TextBox are all good example of this).

-PJ

Brownie said...

Here's a post on the Forums from Dr. WPF on using a style to create a radio button list

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/5137aabc-bb3a-478a-9438-bc93dd9cc0ac/

Vijay said...

Really Great Post