我有一个单选按钮组。选择填写表格不是强制性的。一开始所有单选按钮都未被选中。如果用户无意中点击其中一个,他将无法回到最初状态,因为至少必须选中一个。
那么,我该如何取消单选按钮的选择,而不强迫用户做出不想要的选择?
附:表格是在运行时构建的,并且我正在遵循MVVM设计模式。对于必填项,单选按钮方案非常适合,并且我已经在这种情况下使用了它。
我有一个单选按钮组。选择填写表格不是强制性的。一开始所有单选按钮都未被选中。如果用户无意中点击其中一个,他将无法回到最初状态,因为至少必须选中一个。
那么,我该如何取消单选按钮的选择,而不强迫用户做出不想要的选择?
附:表格是在运行时构建的,并且我正在遵循MVVM设计模式。对于必填项,单选按钮方案非常适合,并且我已经在这种情况下使用了它。
试试这个:
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;
}
}
个人使用 ListBox
,并重写模板使用 RadioButtons
实现此行为。
ListBox
是最适合完成以下所有任务的控件:
我为 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>
而要显示单选按钮本身,通常很简单,就像这样:
<ListBox ItemsSource="{Binding AvailableValues}"
SelectedValue="{Binding SelectedValue}"
Style="{StaticResource RadioButtonListBoxStyle}" />
<RadioButton Checked="RB_Checked" Click="RB_Clicked"/>
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
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;
}
点击事件在选中事件之后触发。
bool? wasChecked = this.IsChecked;
。虽然不确定为什么变量的使用很重要。我认为Peter Moore的解决方案更优雅,因为它不需要代码后台,但这是一个更简单和直接的解决方案。 - jumbo<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 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");
}
}
}
<RadioButton IsChecked="{Binding IsRadioChecked}">Some Radio Button</RadioButton>
private bool _rdoIsChecked;
public bool RdoIsChecked
{
get { return _rdoIsChecked; }
set { SetProperty(ref _rdoIsChecked, !_rdoIsChecked);}
}
嗨,这是如何在每次单击时检查和取消选中单选框的方法。
int click = 0;
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
click++;
((RadioButton)sender).IsChecked = click % 2 == 1 ;
click %= 2;
}
你可以像@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;
}