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!

6 thoughts on “Toggling IsChecked property of a RadioButton using a custom behavior in Silverlight 4

  1. Any idea how you might get the KeyDownHandler to do the same thing, so that when the button has focus and they press the space bar it will check and uncheck?

    I tried adding this handler:

    associatedRadioButton.AddHandler(RadioButton.KeyDownEvent, new KeyEventHandler(OnKeyDownHandler), true);
    ……..
    private void OnKeyDownHandler(object sender, KeyEventArgs e)
    {
    if (e.Key == Key.Space)
    {
    RadioButton associatedRadioButton = this.AssociatedObject as RadioButton;
    if (associatedRadioButton != null && associatedRadioButton.IsChecked.HasValue && associatedRadioButton.IsChecked.Value && listening)
    {
    Dispatcher.BeginInvoke(() => associatedRadioButton.IsChecked = false);
    listening = false;
    }
    }
    }

    But it will only uncheck in the debugger and not normally, which is odd because it’s the same as the mouse button handler.

    Like

  2. I figured it out, it was because I attached the handler to the KeyDown event, and the radiobutton already has one for the KeyUp event, so I changed it to a KeyUp event and it worked.

    Like

  3. I’ve been using this for a while but just ran into a problem with it: if you subscribe to the Click event, the checked value won’t be updated at the time of the Click event when toggling off via this Behavior.

    Taking a look at the disassembly of RadioButton*, I realized all you need to do is this:

    public class RadioButtonUncheckable : RadioButton
    {
    protected override void OnToggle()
    {
    base.IsChecked = !base.IsChecked.Value;
    }
    }

    And use your new RadioButtonUncheckable class instead.

    *RadioButton’s looks like this:
    protected internal override void OnToggle()
    {
    base.IsChecked = true;
    }

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s