如何取消选中 WPF (MVVM) 中的单选按钮
How to Uncheck radio button in WPF (MVVM)
我有一个单选按钮组。选择不是强制填写表格。一开始所有的单选按钮都没有被选中。如果用户无意中点击了其中之一,他就不能返回,因为至少要检查一个。
那么我怎样才能取消选中单选按钮而不强迫用户做出不需要的选择?
p.s。该表单是在 运行 时构建的,我遵循 MVVM 设计模式。
对于强制选择,单选按钮解决方案非常适合,我已经在这种情况下使用了它。
在这种情况下,您不应使用 RadioButton
。此控件的目的是始终选中一个。在您的情况下,我更愿意使用 CheckBox
您的单选按钮:
<RadioButton x:Name="MyRadioButton">Some Radio Button</RadioButton>
隐藏代码:
MyRadioButton.IsChecked = false;
如果您想使用绑定取消选中它,请执行以下操作:
后面的代码:
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(查看):
<RadioButton IsChecked="{Binding IsRadioChecked}">Some Radio Button</RadioButton>
A RadioButton
无法取消选中。
如果您必须继续使用 RadioButton
s,我会添加一个默认的 'Not selected' 选项。
在这种情况下,我更喜欢 ComboBox
顶部有一个空项目或清除按钮。
正如@Tomtom 指出的那样,您可以使用复选框,但这也会提供同时检查多个选项的机会,或实施复杂的机制以确保一次只检查一个选项。
另一个非常便宜的解决方法是在您的单选按钮选项中添加一个额外的条目。
您是如何得知我们的?
- Google
- 一个朋友
- 电视上的广告
- 其他
我同意 Tomtom 的观点,即 RadioButton
可能不是最佳设计选择,但如果该选择超出您的控制范围或出于其他原因有必要,您将需要某种机制来强制取消选择。
这里有一些可能性:
RadioButton
组附近的清除按钮
- 取消选择一个
RadioButton
如果再次点击已经勾选的
- 右键单击选中的
RadioButton
时提供上下文菜单清除选项
由于表单是在 运行 时构建的,因此您需要在创建控件时附加适当的事件处理程序,如下所示:
// 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;
}
就个人而言,当我想要这种行为时,我使用 ListBox
并覆盖模板以使用 RadioButtons
。
它是最适合执行以下所有操作的控件:
- 显示项目列表
- 一次只能选择一项,因此数据模型中只维护一项属性
- 用户可以将所选项目保留为空,表示未选择任何项目
我的 ListBox
自定义样式删除了边框和背景颜色,并使用 RadioButton
绘制每个项目,IsChecked
绑定到 ListBoxItem.IsSelected
。通常是这样的:
<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>
显示 RadioButton 本身通常非常简单,就像这样:
<ListBox ItemsSource="{Binding AvailableValues}"
SelectedValue="{Binding SelectedValue}"
Style="{StaticResource RadioButtonListBoxStyle}" />
肮脏的方法是创建折叠的 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>
如果用户单击已选中的 RadioButton,则选中空的 RadioButton
代码隐藏
private void RadioButton_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var radioButton = sender as RadioButton;
if (radioButton.IsChecked.GetValueOrDefault())
{
rbEmpty.IsChecked = true;
e.Handled = true;
}
}
我在这个场景中使用了一些事件处理程序
<RadioButton Checked="RB_Checked" Click="RB_Clicked"/>
在 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
或者在 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;
}
点击事件在选中事件后触发
试试这个:
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;
}
}
我知道今天回答有点晚了,但我在使用 UWP 时遇到了类似的问题,我认为这可能会有所帮助。我正在开发一个自定义菜单,用户可以在其中选择和取消选择一个选项,我的解决方案显示在以下测试代码中:
主页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>
主页代码隐藏:
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);
}
}
这对我来说效果很好,就我而言,它没有违反任何 MVVM 规则。
您好,这是每次单击单选按钮时选中和取消选中它的方法。
int click = 0;
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
click++;
((RadioButton)sender).IsChecked = click % 2 == 1 ;
click %= 2;
}
我有一个单选按钮组。选择不是强制填写表格。一开始所有的单选按钮都没有被选中。如果用户无意中点击了其中之一,他就不能返回,因为至少要检查一个。
那么我怎样才能取消选中单选按钮而不强迫用户做出不需要的选择?
p.s。该表单是在 运行 时构建的,我遵循 MVVM 设计模式。 对于强制选择,单选按钮解决方案非常适合,我已经在这种情况下使用了它。
在这种情况下,您不应使用 RadioButton
。此控件的目的是始终选中一个。在您的情况下,我更愿意使用 CheckBox
您的单选按钮:
<RadioButton x:Name="MyRadioButton">Some Radio Button</RadioButton>
隐藏代码:
MyRadioButton.IsChecked = false;
如果您想使用绑定取消选中它,请执行以下操作:
后面的代码:
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(查看):
<RadioButton IsChecked="{Binding IsRadioChecked}">Some Radio Button</RadioButton>
A RadioButton
无法取消选中。
如果您必须继续使用 RadioButton
s,我会添加一个默认的 'Not selected' 选项。
在这种情况下,我更喜欢 ComboBox
顶部有一个空项目或清除按钮。
正如@Tomtom 指出的那样,您可以使用复选框,但这也会提供同时检查多个选项的机会,或实施复杂的机制以确保一次只检查一个选项。
另一个非常便宜的解决方法是在您的单选按钮选项中添加一个额外的条目。
您是如何得知我们的?
- 一个朋友
- 电视上的广告
- 其他
我同意 Tomtom 的观点,即 RadioButton
可能不是最佳设计选择,但如果该选择超出您的控制范围或出于其他原因有必要,您将需要某种机制来强制取消选择。
这里有一些可能性:
RadioButton
组附近的清除按钮- 取消选择一个
RadioButton
如果再次点击已经勾选的 - 右键单击选中的
RadioButton
时提供上下文菜单清除选项
由于表单是在 运行 时构建的,因此您需要在创建控件时附加适当的事件处理程序,如下所示:
// 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;
}
就个人而言,当我想要这种行为时,我使用 ListBox
并覆盖模板以使用 RadioButtons
。
它是最适合执行以下所有操作的控件:
- 显示项目列表
- 一次只能选择一项,因此数据模型中只维护一项属性
- 用户可以将所选项目保留为空,表示未选择任何项目
我的 ListBox
自定义样式删除了边框和背景颜色,并使用 RadioButton
绘制每个项目,IsChecked
绑定到 ListBoxItem.IsSelected
。通常是这样的:
<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>
显示 RadioButton 本身通常非常简单,就像这样:
<ListBox ItemsSource="{Binding AvailableValues}"
SelectedValue="{Binding SelectedValue}"
Style="{StaticResource RadioButtonListBoxStyle}" />
肮脏的方法是创建折叠的 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>
如果用户单击已选中的 RadioButton,则选中空的 RadioButton
代码隐藏
private void RadioButton_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var radioButton = sender as RadioButton;
if (radioButton.IsChecked.GetValueOrDefault())
{
rbEmpty.IsChecked = true;
e.Handled = true;
}
}
我在这个场景中使用了一些事件处理程序
<RadioButton Checked="RB_Checked" Click="RB_Clicked"/>
在 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
或者在 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;
}
点击事件在选中事件后触发
试试这个:
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;
}
}
我知道今天回答有点晚了,但我在使用 UWP 时遇到了类似的问题,我认为这可能会有所帮助。我正在开发一个自定义菜单,用户可以在其中选择和取消选择一个选项,我的解决方案显示在以下测试代码中:
主页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>
主页代码隐藏:
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);
}
}
这对我来说效果很好,就我而言,它没有违反任何 MVVM 规则。
您好,这是每次单击单选按钮时选中和取消选中它的方法。
int click = 0;
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
click++;
((RadioButton)sender).IsChecked = click % 2 == 1 ;
click %= 2;
}