Introduction
This article demonstrates the following key features:
A MVVM pattern to handle and manipulate a collection of Radio Buttons.
Stable solution for the IsChecked property without having to usine groups and convertors.
Implicitly set the theme of the project to a windows 8 Metro styled theme for Windows 7 and 8 using MahApps (You will find this .dll file in the packages folder in the source attached to this article.) MahApps web site: http://mahapps.com/
How to segregate views from code in seperate projects. The main reason to do this is if you are going to obfuscate your source you want to keep XAML file seperate as they do not obfuscate correctly.
Creation of a generic reusuable Commands .dll
Background
I am creating this article, because when I was looking for a similar concept i struggled and saw a lot of people were creating their own convertors and basically seemed like a very heavy and tacky approach to handling the same selected functionality as WinForms offers for Radio Buttons.
My approach is less reliant on C# code to handle the single selection of Radio Buttons basically besides your View Model for setting your multiple Radio Button source and selected object to handle whatever purpose you may need my example does not require much code and rather lets the XAML handle the tedious work.
I use a ListBox control to handle the logic so I can them just bind the IsChecked to the parent's IsSelected property that way you can only have a single selected object at a time.
<ListBox ItemsSource="{Binding RadioCollection}" SelectedItem="{Binding SelectedRadio}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<RadioButton
Content="{Binding Header}" ToolTip="{Binding ToolTip}"
IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Margin" Value="5"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
This is an extemely basic project and will give you the good foundation to build up on.
Using the code
Implicitly setting the theme is pretty simple in your App.xaml file add the following MergedDictionaries after referencing the MahApps.dll, there are few accents you can set for example to mention a few: Red, Green, Blue, and Orange. There are also two themes you can set either: BaseDark or BaseLight.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Adding the following attribute inside the opening Window tag
xmlns:con="http://metro.mahapps.com/winfx/xaml/controls"
Now you set your Window tag to con:MetroWindow and then do the same on the code behind. Your code behind on the end product if you are using the MVVM pattern should always look like the following
using MahApps.Metro.Controls;
using System;
using System.Linq;
namespace RadioButtonClient
{
public partial class MainWindow : MetroWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
Do not set DataContext for window in code behind rather add an attribute to you window tag and then set the DataContext in the XAML
xmlns:vm="clr-namespace:RadioButtonCommon;assembly=RadioButtonCommon"
<con:MetroWindow.DataContext>
<vm:RadioControlVM/>
</con:MetroWindow.DataContext>
Your ViewModelBase should be the PropertyChangedEventHandler for the entire solution
public abstract class ViewModelBase : INotifyPropertyChanged
{
#region Implementing PropertyChangedEventHandler
public event PropertyChangedEventHandler PropertyChanged;
public void SetPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion Implementing PropertyChangedEventHandler
}
Create a basic model for the properties you would want your selected Radio Button to have my example just has a Header and ToolTip
public class RadioModel : ViewModelBase
{
#region Header
private string header = string.Empty;
public string Header
{
get { return header; }
set
{
if (value != this.header)
header = value;
this.SetPropertyChanged("Header");
}
}
#endregion Header
#region ToolTip
private string tooltip = string.Empty;
public string ToolTip
{
get { return tooltip; }
set
{
if (value != this.tooltip)
tooltip = value;
this.SetPropertyChanged("ToolTip");
}
}
#endregion ToolTip
#region String Override
public override string ToString()
{
string returnString = string.Empty;
if (!string.IsNullOrEmpty(this.header))
returnString = "Radio button header: {0}. Tooltip: {1}".FormatString(this.header, this.tooltip);
else returnString = "Not set...";
return returnString;
}
#endregion String Override
}
I am not going to go into detail on the ViewModel for this article as you can go through it in the attached source code.
History
First Draft: 2014/08/13