Binding IsChecked property of RadioButton in WPF

If you have tried to bind the RadioButton’s IsChecked property in WPF to an object, you have most likely experienced the following problem: In OneWay bindings it works great. But if you have more than one RadioButtons binded TwoWay and you click on an unchecked one, you were expecting that the object to which the previously checked RadioButton was binded to receive the value of False. But you were wrong in your expectations. That’s because for some reasons Microsoft does not obey bindings and does not pass the False value to the DependencyProperty and instead of that they just assign the value False directly to the property, which ruins the binding.

There are many proposed solutions to this around the internet, problem with all those is that they do not work with dynamically generated controls. So since I had to find a way to make this working with dynamic controls, decided to make a wrapper of the real RadioButton which will correctly Bind in two ways. Here is the code for the wrapper:

using System;
using System.IO;
using System.Printing;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using Microsoft.Win32;

namespace Controls
{
    public class RadioButtonExtended : RadioButton
    {
        static bool m_bIsChanging = false;

        public RadioButtonExtended()
        {
            this.Checked += new RoutedEventHandler(RadioButtonExtended_Checked);
            this.Unchecked += new RoutedEventHandler(RadioButtonExtended_Unchecked);
        }

        void RadioButtonExtended_Unchecked(object sender, RoutedEventArgs e)
        {
            if (!m_bIsChanging)
                this.IsCheckedReal = false;
        }

        void RadioButtonExtended_Checked(object sender, RoutedEventArgs e)
        {
            if (!m_bIsChanging)
                this.IsCheckedReal = true;
        }

        public bool? IsCheckedReal
        {
            get { return (bool?)GetValue(IsCheckedRealProperty); }
            set
            {
                SetValue(IsCheckedRealProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for IsCheckedReal. This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsCheckedRealProperty =
        DependencyProperty.Register("IsCheckedReal", typeof(bool?), typeof(RadioButtonExtended),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal |
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        IsCheckedRealChanged));

        public static void IsCheckedRealChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            m_bIsChanging = true;
            ((RadioButtonExtended)d).IsChecked = (bool)e.NewValue;
            m_bIsChanging = false;
        }
    }
}

So now all you have to do is to use the ExtendedRadioButton instead of the built-in one and bind to the IsCheckedReal property instead of the IsChecked one.
Enjoy 🙂

33 replies
  1. Anonymous
    Anonymous says:

    Also: To get the default BindingMode (and equivalant DependencyProperty) behavior as the regular WPF RadioButton, change the DependencyProperty to:

    public static readonly DependencyProperty IsCheckedRealProperty =
    DependencyProperty.Register(“IsCheckedReal”, typeof(bool?), typeof(ToggleButton),
    new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal |
    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
    IsCheckedRealChanged));

    Reply
  2. Peter Staev
    Peter Staev says:

    Well, m_bIsChanging is static because it is used in a static method. You can change to non static and create a public property that will return m_bIsChanging. After that in the static event you should use

    ((RadioButtonExtended)d).IsChanging = true;

    and

    ((RadioButtonExtended)d).IsChanging = false;

    Reply
  3. Anonymous
    Anonymous says:

    Wow. I spent so much time fighting with this to finally discover it was a bug, then to finally discover a workaround that actually works. Nice job, I am using your class definition to successfully work around the issue for what I was trying to do.

    Reply
  4. mad russian
    mad russian says:

    awesome, thanks man!

    small comment about someone saying you can't apply styles, triggers..
    you totally can!
    just target correct namespaces for that. In the styles example:

    lets say you pull
    xmlns:common="clr-namespace:…RadioButtonExtended folder"

    In the style TargetType="common:RadioButtonExtended"…Sample Setter Property="RadioButton.Margin" Value="8"

    as long as you instanciate the RadioButtonExtended with the same namespace:

    common:adioButtonExtended.. you good to go

    Anyway, thanks for your post

    Reply
  5. ristogod
    ristogod says:

    After trying many other solutions that didn't work. I tried this. Same problem every where. Binding/Convert works once on Load. After that, checking the radio buttons never seems to fire the Binding again. The ConvertBack method in my Binding is never fired.

    Reply
  6. Peter Staev
    Peter Staev says:

    @ristogod
    Did you set your binding to the new IsCheckedReal property or the IsChecked one? Basically it should not matter if there is a converter or not as the converting is fired automatically by the framework itself. Also take a look at the first comment where there is a link that this workaround will not work with styles and triggers.

    Reply
  7. Anonymous
    Anonymous says:

    If I set the IsCheckedReal via databinding during runtime, its unchecks the other radiobuttons correct, but doesn't set the radiobutton as checked. On initialze it works.
    Any suggestions? Thanks in advance.
    Peter

    Reply
  8. Peter Staev
    Peter Staev says:

    I'm not sure understand your explanation, but make sure you have bound all the radio buttons to the IsCheckedReal property and not the original RadioButton.IsChecked property.

    Reply
  9. Anonymous
    Anonymous says:

    Hello Peter
    Thanks for the reply. All of my radio buttons are only bound to IsCheckedReal.
    To clarify: If I set the property on the ViewModel (which is bound with IsCheckedReal) during runtime this button is not visually set (but the internal state is correct)
    I seems to be that the GUI is not updated. Or in other words: if I set the button in the viewmodel during runtime, all buttons are unchecked and none of them is checked.
    In operation with the mouse it works correct.
    Thanks again,
    Peter

    Reply
  10. Anonymous
    Anonymous says:

    Hello Peter
    Thanks for the answer. INotifyPropertyChanged works correct. The changes are comming to the radiobutton. But the radiobutton GUI works not correct if the button is set programmatically. (other buttons will be cleard but none is set)
    Anyway, Thanks for your help.
    Peter

    Reply
  11. Anonymous
    Anonymous says:

    Hello Peter
    Thanks a lot for your help and patience. Now I have made also a small project and there the radiobutton works perfekt. There must be something in my project that disturbs it.
    Peter

    Reply
  12. Anonymous
    Anonymous says:

    Hello Peter
    Now I found the reason for the strange behaviour. I have used GroupName in the radiobuttons. Without it works. My solution is now to overwrite OnChecked and OnUnchecked (and do nothing) in the rb and do the logic in the viewmodel.
    Thanks again, Peter

    Reply
  13. pintu59
    pintu59 says:

    Hi Peter,

    Thanks for your solution. I implemented same in my code and it worked fine for the scenario where normal radio button was causing trouble.
    However on testing further I found few issue in the implementation.

    If we will set value from ViewModel then it sets value perfectly fine but doesn't revert the value of previously selected radio from binded variable. It only reflects on UI.

    so I have come up with some minor changes which takes care of all the problem.

    public class RadioButtonExtended : RadioButton
    {
    static bool m_bIsChanging = false;

    public RadioButtonExtended()
    {
    this.Checked += new RoutedEventHandler(RadioButtonExtended_Checked);
    this.Unchecked += new RoutedEventHandler(RadioButtonExtended_Unchecked);
    }

    void RadioButtonExtended_Unchecked(object sender, RoutedEventArgs e)
    {
    this.IsChecked = false;
    }

    void RadioButtonExtended_Checked(object sender, RoutedEventArgs e)
    {
    this.IsChecked = true;
    }

    public new bool? IsChecked
    {
    get { return (bool?)GetValue(IsCheckedRealProperty); }
    set
    {
    SetValue(IsCheckedRealProperty, value);
    SetValue(IsCheckedProperty, value);
    }
    }

    // Using a DependencyProperty as the backing store for IsCheckedReal. This enables animation, styling, binding, etc…
    public static readonly DependencyProperty IsCheckedRealProperty =
    DependencyProperty.Register("IsChecked", typeof(bool?), typeof(RadioButtonExtended),
    new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal |
    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
    IsCheckedRealChanged));

    public static void IsCheckedRealChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
    if (((RadioButtonExtended)d).IsChecked == (bool)e.NewValue)
    {
    ((RadioButtonExtended)d).IsChecked = (bool)e.NewValue;
    }
    }
    }

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *