Toggling IsChecked property of a RadioButton using a custom behavior in Silverlight 4
I like to use Silverlight controls in interesting ways so that I can re-use their control logic to simplify my own implementations. Most controls at their core represent common scenarios such as selection, state, and enumerated content display. My scenario was I had a collection of fly out panels that I wanted to display one at a time. The radio button provided a great start for this implementation. So I took the RadioButton and skinned it to look like my flyout panels. I could then provide my fly out panels with a ContentTemplate of my choosing, thus making my ability to customize and potentially configure the content on my fly out panels that much simpler.
I used the IsChecked state of the radio button to correspond with whether or not the fly out panel was expanded. This worked brilliantly but I wanted to handle the use case of the user tapping the fly out panel again to collapsed it (without selecting another item). By default, RadioButton doesn’t allow for this. I would have to use a CheckBox to toggle between IsChecked and IsUnchecked. But if I used CheckBox I would lose the RadioButton Group capability that made synchronization of which fly out panel was expanded that much simpler. So I thought I would write a simple Behavior that would enable RadioButtons to uncheck themselves after being checked. It seemed common enough of a use case to implement a behavior for.
public classRadioButtonUncheckBehavior : Behavior<DependencyObject>
{
publicRadioButtonUncheckBehavior()
{
}
}
The OnAttached method provided by the base Behavior class allows you to grab your associated object (in this case our target is a RadioButton) and do things to it, such as wire up events that your behavior wants to handle.
protected override void OnAttached()
{
base.OnAttached();
RadioButton associatedRadioButton = this.AssociatedObject as RadioButton;
if (associatedRadioButton != null)
{
associatedRadioButton.AddHandler(RadioButton.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUpEvent), true);
//associatedRadioButton.AddHandler(RadioButton.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonUpEvent), true);
associatedRadioButton.Checked += new RoutedEventHandler(associatedRadioButton_Checked);
associatedRadioButton.Unchecked += new RoutedEventHandler(associatedRadioButton_Unchecked);
}
}
The below code is what makes it all work. Basically, you need to add actions to the dispatcher’s queue so that your behavior doesn’t start listening before it’s ready (i.e. before the IsChecked property is able to be updated). You need to make sure that when the RadioButton is Checked you turn listening on and when it is Unchecked you will turn listening off. Otherwise you will constantly cause the RadioButton to be Unchecked.
bool listening = false;
void associatedRadioButton_Unchecked(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(() => listening = false);
}
private void associatedRadioButton_Checked(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(() => listening = true);
}
private void OnMouseLeftButtonUpEvent(object sender, MouseButtonEventArgs args)
{
RadioButton associatedRadioButton = this.AssociatedObject as RadioButton;
if (associatedRadioButton != null && associatedRadioButton.IsChecked.HasValue && associatedRadioButton.IsChecked.Value && listening)
{
Dispatcher.BeginInvoke(() => associatedRadioButton.IsChecked = false);
listening = false;
}
}
Done!