代码之家  ›  专栏  ›  技术社区  ›  Jason

三态复选框-如何更改状态顺序

  •  11
  • Jason  · 技术社区  · 16 年前

    我的应用程序中有一个使用三态模式的复选框。此模式的正常行为似乎在空、假、真之间循环。

    我想改变这个行为,使它在空、真、假之间循环。

    最好的方法是什么?

    我尝试添加类似于以下内容的单击处理程序:

    void cb_Click(object sender, RoutedEventArgs e)
    {
        if (((CheckBox)e.Source).IsChecked.HasValue == false)
        {
            ((CheckBox)e.Source).IsChecked = true;
            return;
        }
    
        if (((CheckBox)e.Source).IsChecked == true)
        {
            ((CheckBox)e.Source).IsChecked = false;
            return;
        }
    
        if (((CheckBox)e.Source).IsChecked == false)
        {
            ((CheckBox)e.Source).IsChecked = null;
            return;
        }
    
    }
    

    但这似乎完全禁用了复选框。我很肯定我遗漏了一些显而易见的东西。

    5 回复  |  直到 6 年前
        1
  •  24
  •   Thomas Levesque    16 年前

    我猜事件处理程序和默认行为只是取消对方的效果,所以复选框似乎被禁用了…

    实际上,我最近不得不做同样的事情。我必须继承 CheckBox 超驰 OnToggle :

    public class MyCheckBox : CheckBox
    {
    
    
        public bool InvertCheckStateOrder
        {
            get { return (bool)GetValue(InvertCheckStateOrderProperty); }
            set { SetValue(InvertCheckStateOrderProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for InvertCheckStateOrder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvertCheckStateOrderProperty =
            DependencyProperty.Register("InvertCheckStateOrder", typeof(bool), typeof(MyCheckBox), new UIPropertyMetadata(false));
    
        protected override void OnToggle()
        {
            if (this.InvertCheckStateOrder)
            {
                if (this.IsChecked == true)
                {
                    this.IsChecked = false;
                }
                else if (this.IsChecked == false)
                {
                    this.IsChecked = this.IsThreeState ? null : (bool?)true;
                }
                else
                {
                    this.IsChecked = true;
                }
            }
            else
            {
                base.OnToggle();
            }
        }
    }
    
        2
  •  0
  •   casiosmu    7 年前

    仅为完整起见,这里还提供了Windows窗体的解决方案。我们必须超越 OnClick 方法,重写 OnStateChanged 导致显示错误(如果操作不正确,则会导致stackoverflow)。

    /// <summary>
    /// A <see cref="System.Windows.Forms.CheckBox"/> with the ability to reverse the checkstate order.
    /// </summary>
    /// <seealso cref="System.Windows.Forms.CheckBox" />
    public class CheckBoxReversible : CheckBox
    {
        private bool FInvertCheckStateOrder;
    
        /// <summary>
        /// Gets or sets a value indicating whether to invert the check state order from [Indeterminate->Unchecked->Checked] to [Indeterminate->Checked->Unchecked].
        /// </summary>
        /// <value>
        ///   <c>true</c> to invert the check state order; otherwise, <c>false</c>.
        /// </value>
        public bool InvertCheckStateOrder
        {
            get { return FInvertCheckStateOrder; }
            set { FInvertCheckStateOrder = value; }
        }
    
        /// <summary>
        /// Löst das <see cref="E:System.Windows.Forms.Control.Click" />-Ereignis aus.
        /// </summary>
        /// <param name="e">Eine Instanz der <see cref="T:System.EventArgs" />-Klasse, die die Ereignisdaten enthält.</param>
        protected override void OnClick(EventArgs e)
        {
            if (this.InvertCheckStateOrder)
            {
                if (this.CheckState == CheckState.Indeterminate)
                    this.CheckState = CheckState.Checked;
                else
                    if (this.CheckState == CheckState.Checked)
                        this.CheckState = CheckState.Unchecked;
                    else
                        if (this.CheckState == CheckState.Unchecked)
                            this.CheckState = this.ThreeState ? CheckState.Indeterminate : CheckState.Checked;
            }
            else
                base.OnClick(e);
        }
    }
    
        3
  •  0
  •   Iñigo Panera    7 年前

    非常感谢,使用ToggleButton解决类似的行为非常有用。

    class InvertedToggleButton : ToggleButton
    {
        public bool InvertCheckStateOrder
        {
            get { return (bool)GetValue(InvertCheckStateOrderProperty); }
            set { SetValue(InvertCheckStateOrderProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for InvertCheckStateOrder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InvertCheckStateOrderProperty = DependencyProperty.Register("InvertCheckStateOrder", typeof(bool), typeof(ToggleButtonInvertido), new UIPropertyMetadata(false));
    
        protected override void OnToggle()
        {
            if (this.InvertCheckStateOrder)
            {
                if (this.IsChecked == true)
                {
                    this.IsChecked = false;
                }
                else if (this.IsChecked == false)
                {
                    this.IsChecked = this.IsThreeState ? null : (bool?)true;
                }
                else
                {
                    this.IsChecked = true;
                }
            }
            else
            {
                if (!this.IsChecked.HasValue)
                    this.IsChecked = true;
                else
                    base.OnToggle();
            }
        }
    }
    
        4
  •  0
  •   Jinlye    7 年前

    正如所指出的,没有 CheckBox.OnToggle() 在WinForms中重写,因此在这种情况下 CheckBox.OnClick() 是去哪里。

    以下是WinForms复选框的最小实现,该复选框循环未选中->不确定->选中->未选中…,而不是默认的未选中->选中->不确定->未选中…

    using System;
    using System.Windows.Forms;
    
    public class MyCheckBox : CheckBox
    {
        protected override void OnClick(EventArgs e)
        {
            switch(this.CheckState)
            {
                case CheckState.Indeterminate:
                    this.CheckState = CheckState.Checked;
                    break;
                case CheckState.Checked:
                    this.CheckState = CheckState.Unchecked;
                    break;
                case CheckState.Unchecked:
                    this.CheckState = this.ThreeState ? CheckState.Indeterminate : CheckState.Checked;
                    break;
                default:
                    throw new ApplicationException("Unexpected CheckState: " + this.CheckState.ToString());
            }
        }
    }
    

    或者,如果您乐于引入对Windows分配给checkstate状态的int值的依赖关系,那么这也可以工作:

    using System;
    using System.Windows.Forms;
    
    public class MyCheckBox : CheckBox
    {
        protected override void OnClick(EventArgs e)
        {
            CheckState newState = this.CheckState - 1;
            if (newState < 0) 
            {
                newState = this.ThreeState ? CheckState.Indeterminate : CheckState.Checked;
            }
            this.CheckState = newState;
        }
    }
    
        5
  •  0
  •   Roberto    6 年前

    接受的解决方案是最好的,但是如果您不想创建子类,只需执行以下操作:

    void chkbokHeader_Click(object sender, RoutedEventArgs e)
    {
      CheckBox senderChk = sender as CheckBox;
      bool bCheck = false;
      //here, the status is already changed, so rechange:
      if (senderChk.IsChecked == true) // from UNCHECKED
        bCheck = true;
      else if (senderChk.IsChecked == false) //from INDETERMINATE
        bCheck = true;
      else //from CHECKED
        bCheck = false;
    
      senderChk.IsChecked = bCheck;
      e.Handled = true;
    }
    

    它创建(选中)序列:不确定->真->假->真->假->真->…