Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

WPF Behavior to Reset RadioButtons on VisibilityChanged

5.00/5 (5 votes)
2 Apr 2018CPOL2 min read 10.3K   69  
This tip provides a behavior that will reset all RadioButton controls within a Control that has this behavior when the Visibility changes.

Introduction

There are times when there could be a number of RadioButton controls, and after the containing Control loses Visibility, it is desirable that none of the RadioButton controls be selected. This can be done usually in the associated ViewModel, but it could be easier just to have the controls reset automatically, sort of like when you initially create a View, then any contained RadioButton is false unless the ViewModel has set it to true, and the ViewModel will also have the default of false for any property, including those associated with a RadioButton IsChecked property.

The Behavior

The following is the C# code for the behavior:

C#
public class ResetRadioButtonOnVisibilityBehavior
{
    public static bool GetEnable(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnableProperty);
    }

    public static void SetEnable(DependencyObject obj, bool value)
    {
        obj.SetValue(EnableProperty, value);
    }

    public static readonly DependencyProperty EnableProperty =
        DependencyProperty.RegisterAttached("Enable",
            typeof(bool), typeof(ResetRadioButtonOnVisibilityBehavior),
            new UIPropertyMetadata(OnEnablePropertyChanged));

    private static void OnEnablePropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
    {
        var element = (FrameworkElement) d;
        if ((bool)e.NewValue)
            element.IsVisibleChanged += ElementOnIsVisibleChanged;
        else
            element.IsVisibleChanged -= ElementOnIsVisibleChanged;
     }

    private static void ElementOnIsVisibleChanged(object sender,
            DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        var dependencyObject = (UIElement)sender;

        if (!(bool) dependencyPropertyChangedEventArgs.NewValue)
        {
            var checkBoxes = FindVisualChildren<ToggleButton>(dependencyObject).ToList();
            checkBoxes.ForEach(i => i.IsChecked = false);
        }
    }

    #region private static
    private static IEnumerable<T> FindVisualChildren<T>(DependencyObject root)
            where T : DependencyObject
    {
        if (root != null)
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(root, i);
                if (child is T) yield return (T)child;
                foreach (T childOfChild in FindVisualChildren<T>(child))
                    yield return childOfChild;
            }
    }
    #endregion
}

There is a single bool EnableProperty DependencyProperty that is set to true to enable the behavior. The event handler for its DependencyProperty changed event, OnEnablePropertyChanged, adds the method ElementOnIsVisibleChanged to the IsVisibleChanged event (or removes it if set to false). When the e.NewValue part of the DependencyPropertyChangedEventArgs argument is false, then the Control's VisualChildren are searched for any instances of a RadioButton, and any RadioButton controls that are found have their IsChecked property set to false.

I have included the private method FindVisualChildren in the behavior for probability, but more than likely would want to put this code in a separate class within the solution for utility code.

The Sample

To use the sample, you just have to click the ToggleButton on the Window so that RadioButton controls within a StackPanel to which this behavior is attached are visible, then can select any number of the RadioButton controls which results in exactly one of them being set. Hide and show the RadioButton controls using the ToggleButton. Notice that none of the RadioButton controls is set when the StackPanel Visibility is Visible.

Using the Code

Using this behavior is like any other behavior, the behavior is included in the XAML for the parent or grandparent, or any other ancestor Control containing RadioButton controls. Its Enable property just has to be set to true:

XML
 <StackPanel HorizontalAlignment="Center"
            VerticalAlignment="Center"
            local:ResetRadioButtonOnVisibilityBehavior.Enable="True"
            Visibility="{Binding ElementName=ToggleButton,
                                 Path=IsChecked,
                                 Converter={local:IsTrueConverter},
                                 ConverterParameter=Visible:Hidden}">
    <RadioButton Content="RadioButton One" />
    <RadioButton Content="RadioButton One" />
    <RadioButton Content="RadioButton One" />
    <RadioButton Content="RadioButton One" />
</StackPanel>

Design Issues

This is quite a stupid design since all instances of RadioButton controls within the Control that this behavior is attached will be reset. This could be considered a good or bad thing because the way a group of RadioButton controls act is that checking a RadioButton will only reset those RadioButton controls directly within the same container. However, if it is desired to reset one group of contained RadioButton controls, then likely that want to reset all.

This behavior affects RadioButton controls but could also be very easily modified to work on CheckBox or ToggleButton controls.

History

  • 04/02/2018: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)