TriState Checkbox - как изменить порядок состояний - PullRequest
11 голосов
/ 28 августа 2009

В моем приложении есть CheckBox, использующий режим TriState. Нормальное поведение для этого режима, по-видимому, циклично: ноль, ложь, истина.

Я бы хотел изменить это поведение, чтобы оно переключалось между нулем, истиной, ложью.

Какой лучший способ сделать это?

Я пытался добавить обработчик кликов, подобный этому:

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 ]

24 голосов
/ 28 августа 2009

Полагаю, что обработчик событий и поведение по умолчанию просто отменяют эффекты друг друга, поэтому флажок кажется отключенным ...

На самом деле недавно мне пришлось сделать то же самое. Мне пришлось наследовать от 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();
        }
    }
}
0 голосов
/ 28 февраля 2019

Принятое решение является лучшим, но если вы не хотите создавать подкласс, просто сделайте что-то вроде:

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

Создает (проверено) последовательность: undeterminate -> true -> false -> true -> false -> true -> ...

0 голосов
/ 04 декабря 2018

Как указывалось, в WinForms нет CheckBox.OnToggle() для переопределения, поэтому в этом случае 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());
        }
    }
}

Или, если вы довольны введением зависимости от того, какие значения int присваивает Windows тому или иному состоянию CheckState, это также работает:

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 голосов
/ 02 ноября 2018

Большое спасибо, было очень полезно решить подобное поведение с 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 голосов
/ 25 октября 2018

Только для полноты здесь дополнительно решение для Windows-Forms. Мы должны переопределить метод OnClick, переопределив OnStateChanged, что приведет к ошибке отображения (и переполнению стека при неправильном выполнении).

/// <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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...