TriState Checkbox - how to change the order of the states

后端 未结 5 643
走了就别回头了
走了就别回头了 2020-12-06 17:03

I have a CheckBox in my application that is using the TriState mode. The normal behavior for this mode seems to be cycling between null, false, true.

I\'d like to c

相关标签:
5条回答
  • 2020-12-06 17:47

    Only for completeness here additionally the solution for Windows-Forms. We have to override the OnClick method, overriding OnStateChanged results in display bug (and stackoverflow if done incorrectly).

    /// <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);
        }
    }
    
    0 讨论(0)
  • 2020-12-06 17:49

    As pointed out, there is no CheckBox.OnToggle() to override in WinForms, so in that case CheckBox.OnClick() is where to head for.

    Here's a minimal implementation of a WinForms checkbox that cycles Unchecked -> Indeterminate -> Checked -> Unchecked..., instead of the default Unchecked -> Checked -> Indeterminate -> Unchecked...

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

    Or if you are happy about introducing a dependency on what int values Windows assigns to what states of CheckState, this works also:

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-06 17:51

    I guess the event handler and the default behavior are just cancelling each other's effects, so the checkbox seems disabled...

    Actually I recently had to do the same thing. I had to inherit from CheckBox and override 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();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-06 17:55

    Accepted solution is the best, but if you don't want to create a subclass, just do something as:

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

    It create the (checked) sequence: indeterminate -> true -> false -> true -> false -> true -> ...

    0 讨论(0)
  • 2020-12-06 17:55

    Thank you very much, it has been very useful to solve a similar behavior with 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();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题