Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Uncheck radio button in WPF (MVVM)

I have a radio buttons group. The choice is not mandatory to fill the form. At the beginning all the radio buttons are unchecked. If the user unintentionally clicks on one of them, he can not go back, because at least one has to be checked.

So How can I uncheck a radio button and not force the user to make an unwanted choice?

p.s. the form is built at run-time and I am following the MVVM design pattern. For Mandatory choices, the radio buttons solution fit very well and I already use it in this case.

like image 586
overcomer Avatar asked Sep 22 '15 14:09

overcomer


3 Answers

Try this:

public class OptionalRadioButton : RadioButton
{
    #region bool IsOptional dependency property
    public static readonly DependencyProperty IsOptionalProperty = 
        DependencyProperty.Register(
            "IsOptional", 
            typeof(bool), 
            typeof(OptionalRadioButton), 
            new PropertyMetadata((bool)true,
                (obj, args) =>
                {
                    ((OptionalRadioButton)obj).OnIsOptionalChanged(args);
                }));
    public bool IsOptional
    {
        get
        {
            return (bool)GetValue(IsOptionalProperty);
        }
        set
        {
            SetValue(IsOptionalProperty, value);
        }
    }
    private void OnIsOptionalChanged(DependencyPropertyChangedEventArgs args)
    {
        // TODO: Add event handler if needed
    }
    #endregion

    protected override void OnClick()
    {
        bool? wasChecked = this.IsChecked;
        base.OnClick();
        if ( this.IsOptional && wasChecked == true )
            this.IsChecked = false;
    }
}
like image 113
Peter Moore Avatar answered Oct 11 '22 02:10

Peter Moore


Personally when I want this behavior I use a ListBox with the Template overwritten to use RadioButtons.

It's the best control suited to do all of the following :

  • display a list of items
  • only one item can be selected at a time, so only one property maintained in data model
  • user can leave selected item as null, indicating no item is selected

My custom style for the ListBox removes the borders and background color, and draws each item using a RadioButton with the IsChecked bound to the ListBoxItem.IsSelected. Typically something like this :

<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2, 2, 2, 0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent">
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                    IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

And to display the RadioButtons themselves is usually something very simple, like this :

<ListBox ItemsSource="{Binding AvailableValues}"
         SelectedValue="{Binding SelectedValue}"
         Style="{StaticResource RadioButtonListBoxStyle}" />
like image 22
Rachel Avatar answered Oct 11 '22 02:10

Rachel


I used for this Scenario some Eventhandlers

<RadioButton Checked="RB_Checked" Click="RB_Clicked"/>

In the Codebehind of the XAML:

Private JustChecked as Boolean

Private Sub RB_Checked(sender As Object, e As RoutedEventArgs)
    Dim s As RadioButton = sender
    ' Action on Check...
    JustChecked = True
End Sub

Private Sub RB_Clicked(sender As Object, e As RoutedEventArgs)
    If JustChecked Then
        JustChecked = False
        e.Handled = True
        Return
    End If
    Dim s As RadioButton = sender
    If s.IsChecked Then s.IsChecked = False        
End Sub

Or in C#

private bool JustChecked;
private void RB_Checked(object sender, RoutedEventArgs e)
{
    RadioButton s = sender;
    // Action on Check...
    JustChecked = true;
}

private void RB_Clicked(object sender, RoutedEventArgs e)
{
    if (JustChecked) {
        JustChecked = false;
        e.Handled = true;
        return;
    }
    RadioButton s = sender;
    if (s.IsChecked)
        s.IsChecked = false;
}

Click Event fires after Checked Event

like image 22
dba Avatar answered Oct 11 '22 04:10

dba