TriState Checkbox - how to change the order of the states
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();
}
}
}
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);
}
}
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 -> ...