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

问题描述 投票:0回答:13

我有一个单选按钮组。该选择并不强制要求填写表格。一开始,所有单选按钮都未被选中。如果用户无意中点击了其中一项,他就无法返回,因为至少需要检查一项。

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

附注该表单是在运行时构建的,我遵循 MVVM 设计模式。 对于强制选择,单选按钮解决方案非常适合,我已经在这种情况下使用了它。

c# wpf radio-button
13个回答
20
投票

试试这个:

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

11
投票

就我个人而言,当我想要这种行为时,我使用

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>

显示单选按钮本身通常非常简单,如下所示:

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

7
投票

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

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

单击事件在选中事件后触发


3
投票

肮脏的方法是创建折叠的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;
        }
    }

2
投票

您的单选按钮:

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

2
投票

如果您使用 MVVM,我只是在绑定到每个单选按钮的 IsChecked 属性的属性的 setter 中进行了一些处理。这基本上确保了当用户单击 radiobtn 选项时,IsChecked 值将设置为与之前相反的值。这是我的代码示例:

private bool _rdoIsChecked;
    public bool RdoIsChecked
    {
        get { return _rdoIsChecked; }
        set { SetProperty(ref _rdoIsChecked, !_rdoIsChecked);}

    }

1
投票

嗨,这是每次单击单选按钮时选中和取消选中它的方法。

  int click = 0;
    private void RadioButton_Click(object sender, RoutedEventArgs e)
    {
        click++;
        ((RadioButton)sender).IsChecked = click % 2 == 1 ;
        click %= 2;
    }

0
投票

在这种情况下,您不应使用

RadioButton
。此控件的目的是始终检查一个。在你的场景中,我更喜欢使用
CheckBox


0
投票

正如@Tomtom 指出的那样,您可以使用复选框,但这也提供了同时检查多个选项的机会,或者您必须实现一种复杂的机制来确保只有一个选项是一次检查一下。

另一个非常便宜的解决方法是在单选按钮选择中添加一个额外的条目。

您是如何得知我们的?

  • 谷歌
  • 一个朋友
  • 电视广告
  • 其他

0
投票

我同意 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;
    }

0
投票

我知道我参加聚会迟到了 8 年,但有一个事件/代表称为“未检查”


-1
投票

A

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


-1
投票

我知道现在回答有点晚了,但我在使用 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 规则。

© www.soinside.com 2019 - 2024. All rights reserved.