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?
ps 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.
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;
}
}
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 :
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}" />
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
Your radio button:
<RadioButton x:Name="MyRadioButton">Some Radio Button</RadioButton>
Code Behind:
MyRadioButton.IsChecked = false;
Code behind:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
#endregion
private bool _isRadioChecked;
public bool IsRadioChecked
{
get
{
return _isRadioChecked;
}
set
{
_isRadioChecked = value;
OnPropertyChanged("IsRadioChecked");
}
}
}
xaml (view):
<RadioButton IsChecked="{Binding IsRadioChecked}">Some Radio Button</RadioButton>
The dirty way is to create collapsed RadioButton
<StackPanel>
<RadioButton Content="Option 1" GroupName="optionSet1" PreviewMouseDown="RadioButton_OnPreviewMouseDown"/>
<RadioButton Content="Option 2" GroupName="optionSet1" PreviewMouseDown="RadioButton_OnPreviewMouseDown"/>
<RadioButton GroupName="optionSet1" x:Name="rbEmpty" Visibility="Collapsed" />
</StackPanel>
And check the empty RadioButton if user click on already checked RadioButton
Code behind
private void RadioButton_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var radioButton = sender as RadioButton;
if (radioButton.IsChecked.GetValueOrDefault())
{
rbEmpty.IsChecked = true;
e.Handled = true;
}
}
In this case you shouldn't use a RadioButton
. The purpose of this control is that always one is checked. In your scenario I would prefer to use a CheckBox
You could, as @Tomtom pointed out, use Checkboxes, but that would also give the opportunity to check more than one option at the same time, or you'd have to implement a complex mechanism to make sure only one option is checked at a time.
Another very cheap workaround would be to add an extra entry in your radio button choices.
How did you hear about us ?
I agree with Tomtom that RadioButton
is perhaps not the best design choice, but if that selection is out of your control or it is necessary for other reasons, you will need some mechanism by which to force the deselect.
RadioButton
group RadioButton
that is already checked if it is clicked again.RadioButton
is right clickedSince the form is built at run-time, you will need to attach the appropriate event handler when you are creating the control, like so:
// Create an instance of the control
var controlType = typeof(Control).Assembly.GetType(fullyQualifiedControl, true);
var control = Activator.CreateInstance(controlType);
switch (fullyQualifiedControl)
{
case "System.Windows.Controls.RadioButton":
((RadioButton)control).Checked += new RoutedEventHandler(DataDrivenControl_Checked);
((RadioButton)control).Unchecked += new RoutedEventHandler(DataDrivenControl_UnChecked);
break;
}
I know that this is a bit late in the day for an answer but I had a similar problem using UWP and I thought that this might help. I was developing a custom menu where the user can pick and unpick an option and my solution is shown in the following test code:
Main Page Xaml:
<Grid>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<RadioButton x:Name="RB1" GroupName="RBTest" Content="Item No. 1" Click="RBtn_Click"/>
<RadioButton x:Name="RB2" GroupName="RBTest" Content="Item No. 2" Click="RBtn_Click"/>
<RadioButton x:Name="RB3" GroupName="RBTest" Content="Item No. 3" Click="RBtn_Click"/>
<RadioButton x:Name="RB4" GroupName="RBTest" Content="Item No. 4" Click="RBtn_Click"/>
<RadioButton x:Name="RB5" GroupName="RBTest" Content="Item No. 5" Click="RBtn_Click"/>
</StackPanel>
</Grid>
Main Page Code Behind:
public sealed partial class MainPage : Page
{
private bool rb1PrevState;
private bool rb2PrevState;
private bool rb3PrevState;
private bool rb4PrevState;
private bool rb5PrevState;
public MainPage()
{
this.InitializeComponent();
rb1PrevState = this.RB1.IsChecked.Value;
rb2PrevState = this.RB2.IsChecked.Value;
rb3PrevState = this.RB3.IsChecked.Value;
rb4PrevState = this.RB4.IsChecked.Value;
rb5PrevState = this.RB5.IsChecked.Value;
}
private void RBtn_Click(object sender, RoutedEventArgs e)
{
RadioButton rbtn = sender as RadioButton;
if (rbtn != null)
{
if (rbtn.IsChecked.Value == true)
{
switch (rbtn.Name)
{
case "RB1":
if (rb1PrevState == true)
{
rbtn.IsChecked = false;
rb1PrevState = false;
}
else
{
rb1PrevState = true;
ResetRBPrevStates("RB1");
}
break;
case "RB2":
if (rb2PrevState == true)
{
rbtn.IsChecked = false;
rb2PrevState = false;
}
else
{
rb2PrevState = true;
ResetRBPrevStates("RB2");
}
break;
case "RB3":
if (rb3PrevState == true)
{
rbtn.IsChecked = false;
rb3PrevState = false;
}
else
{
rb3PrevState = true;
ResetRBPrevStates("RB3");
}
break;
case "RB4":
if (rb4PrevState == true)
{
rbtn.IsChecked = false;
rb4PrevState = false;
}
else
{
rb4PrevState = true;
ResetRBPrevStates("RB4");
}
break;
case "RB5":
if (rb5PrevState == true)
{
rbtn.IsChecked = false;
rb5PrevState = false;
}
else
{
rb5PrevState = true;
ResetRBPrevStates("RB5");
}
break;
default:
break;
}
}
}
}
private void ResetRBPrevStates(string _excludeRB)
{
rb1PrevState = (_excludeRB == "RB1" ? rb1PrevState : false);
rb2PrevState = (_excludeRB == "RB2" ? rb2PrevState : false);
rb3PrevState = (_excludeRB == "RB3" ? rb3PrevState : false);
rb4PrevState = (_excludeRB == "RB4" ? rb4PrevState : false);
rb5PrevState = (_excludeRB == "RB5" ? rb5PrevState : false);
}
}
This worked well for me and, a far as I'm concerned, doesn't break any MVVM rules.
hi this is how to check and uncheck the radio button each times click on it.
int click = 0;
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
click++;
((RadioButton)sender).IsChecked = click % 2 == 1 ;
click %= 2;
}
A RadioButton
cannot be unchecked. If you have to keep using RadioButton
s, I would add a default 'Not selected' choice. In this case, I prefer a ComboBox
with an empty item or clear button at the top.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.