【问题标题】:How to Uncheck radio button in WPF (MVVM)如何取消选中 WPF (MVVM) 中的单选按钮
【发布时间】:2015-12-19 14:33:07
【问题描述】:

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

那么我怎样才能取消选中单选按钮而不强迫用户做出不需要的选择呢?

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

【问题讨论】:

    标签: c# wpf radio-button


    【解决方案1】:

    试试这个:

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

    【讨论】:

    • 这很棒。如果您使用它,请确保您只是在自己的 cs 文件中创建它,不要尝试使用自己的 XAML 创建新的 UserControl。
    【解决方案2】:

    当我想要这种行为时,我个人使用 ListBox 并覆盖模板以使用 RadioButtons

    这是最适合执行以下所有操作的控件:

    • 显示项目列表
    • 一次只能选择一项,因此数据模型中只维护一个属性
    • 用户可以将选中的项目保留为空,表示没有选中任何项目

    我对@9​​87654323@ 的自定义样式删除了边框和背景颜色,并使用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}" />
    

    【讨论】:

    • 不错的瑞秋,我喜欢你的解决方案。
    【解决方案3】:

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

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

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

    【讨论】:

    • 彼得摩尔解决方案不需要变量。
    • Peter Moore 的解决方案中实际上也使用了大多数相同的变量:bool? wasChecked = this.IsChecked;。不知道为什么变量的使用很重要。我会说 Peter Moore 的解决方案更优雅,因为它不需要后面的代码,但这是一个更简单、更直接的解决方案。
    【解决方案4】:

    您的单选按钮:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        在这种情况下,您不应使用RadioButton。此控件的目的是始终选中一个。在您的情况下,我更愿意使用CheckBox

        【讨论】:

        • 不过要小心:使用复选框,您可以一次选择多个选项,而不是单选按钮。
        • @Tomtom 我不同意,因为选择应该只有一个(典型的单选按钮选择),但不是必须回答。
        • 没有帮助。另外,要求检查一项和只检查一项,以及一项或一项都不检查是有区别的。
        【解决方案7】:

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

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

        你是怎么知道我们的?

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

        【讨论】:

        • 问题是我不想强迫用户做出非强制性的选择。
        • 你不必强迫他们。如果他一开始不做出选择,就不会被强制执行。另一种选择是有一个 RESET FORM 按钮并通过后面的代码取消选择它
        • 首先,想象一下你希望你的用户界面如何表现,有一个心理图景:你希望你的用户如何撤销他不打算做的选择?一旦你回答了这个问题,我们可以进一步帮助你:)
        • 是的,我考虑过重置按钮,但表单可能很大,我认为重置表单不是一个好选择。
        • 然后是一个用于重置单选按钮的按钮,但这似乎不是一个很好的用户体验。你必须先弄清楚你的用户体验:)
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          您好,这是每次单击单选按钮时检查和取消选中的方法。

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

          【讨论】:

            【解决方案10】:

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

            【讨论】:

              【解决方案11】:

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

              【讨论】:

                猜你喜欢
                • 2012-12-10
                • 1970-01-01
                • 1970-01-01
                • 2014-04-25
                • 1970-01-01
                • 2011-01-08
                • 2011-02-05
                • 2011-08-19
                相关资源
                最近更新 更多