繁体   English   中英

如何取消选中 WPF (MVVM) 中的单选按钮

[英]How to Uncheck radio button in WPF (MVVM)

我有一个单选按钮组。 选择不是填写表格的强制性要求。 开始时,所有单选按钮都未选中。 如果用户无意中点击了其中之一,他将无法返回,因为必须至少检查一个。

那么如何取消选中单选按钮而不强迫用户做出不需要的选择呢?

ps 表单是在运行时构建的,我遵循 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自定义样式删除了边框和背景颜色,并使用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>

并且显示 RadioButtons 本身通常非常简单,如下所示:

<ListBox ItemsSource="{Binding AvailableValues}"
         SelectedValue="{Binding SelectedValue}"
         Style="{StaticResource RadioButtonListBoxStyle}" />

我在这个场景中使用了一些事件处理程序

<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;
}

单击事件在检查事件后触发

您的单选按钮:

<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>

肮脏的方法是创建折叠的 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 此控件的目的是始终选中一个。 在您的场景中,我更喜欢使用CheckBox

正如@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;
    }

我知道今天的答案有点晚了,但我在使用 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;
    }

RadioButton选中RadioButton 如果您必须继续使用RadioButton s,我会添加一个默认的“未选择”选项。 在这种情况下,我更喜欢顶部带有空项目或清除按钮的ComboBox

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM