Browse Source

Implement events for ToggleButton.

pull/3427/head
Dariusz Komosinski 6 years ago
parent
commit
35f26081c6
  1. 122
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  2. 54
      tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs

122
src/Avalonia.Controls/Primitives/ToggleButton.cs

@ -7,8 +7,14 @@ using Avalonia.Data;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
/// <summary>
/// Represents a control that a user can select (check) or clear (uncheck). Base class for controls that can switch states.
/// </summary>
public class ToggleButton : Button public class ToggleButton : Button
{ {
/// <summary>
/// Defines the <see cref="IsChecked"/> property.
/// </summary>
public static readonly DirectProperty<ToggleButton, bool?> IsCheckedProperty = public static readonly DirectProperty<ToggleButton, bool?> IsCheckedProperty =
AvaloniaProperty.RegisterDirect<ToggleButton, bool?>( AvaloniaProperty.RegisterDirect<ToggleButton, bool?>(
nameof(IsChecked), nameof(IsChecked),
@ -17,9 +23,30 @@ namespace Avalonia.Controls.Primitives
unsetValue: null, unsetValue: null,
defaultBindingMode: BindingMode.TwoWay); defaultBindingMode: BindingMode.TwoWay);
/// <summary>
/// Defines the <see cref="IsThreeState"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsThreeStateProperty = public static readonly StyledProperty<bool> IsThreeStateProperty =
AvaloniaProperty.Register<ToggleButton, bool>(nameof(IsThreeState)); AvaloniaProperty.Register<ToggleButton, bool>(nameof(IsThreeState));
/// <summary>
/// Defines the <see cref="Checked"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> CheckedEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>(nameof(Checked), RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="Unchecked"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> UncheckedEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>(nameof(Unchecked), RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="Unchecked"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> IndeterminateEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>(nameof(Indeterminate), RoutingStrategies.Bubble);
private bool? _isChecked = false; private bool? _isChecked = false;
static ToggleButton() static ToggleButton()
@ -27,14 +54,49 @@ namespace Avalonia.Controls.Primitives
PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == true, ":checked"); PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == true, ":checked");
PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == false, ":unchecked"); PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == false, ":unchecked");
PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == null, ":indeterminate"); PseudoClass<ToggleButton, bool?>(IsCheckedProperty, c => c == null, ":indeterminate");
IsCheckedProperty.Changed.AddClassHandler<ToggleButton>((x, e) => x.OnIsCheckedChanged(e));
}
/// <summary>
/// Raised when a <see cref="ToggleButton"/> is checked.
/// </summary>
public event EventHandler<RoutedEventArgs> Checked
{
add { AddHandler(CheckedEvent, value); }
remove { RemoveHandler(CheckedEvent, value); }
}
/// <summary>
/// Raised when a <see cref="ToggleButton"/> is unchecked.
/// </summary>
public event EventHandler<RoutedEventArgs> Unchecked
{
add { AddHandler(UncheckedEvent, value); }
remove { RemoveHandler(UncheckedEvent, value); }
}
/// <summary>
/// Raised when a <see cref="ToggleButton"/> is neither checked nor unchecked.
/// </summary>
public event EventHandler<RoutedEventArgs> Indeterminate
{
add { AddHandler(IndeterminateEvent, value); }
remove { RemoveHandler(IndeterminateEvent, value); }
} }
/// <summary>
/// Gets or sets whether the <see cref="ToggleButton"/> is checked.
/// </summary>
public bool? IsChecked public bool? IsChecked
{ {
get { return _isChecked; } get { return _isChecked; }
set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); } set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); }
} }
/// <summary>
/// Gets or sets a value that indicates whether the control supports three states.
/// </summary>
public bool IsThreeState public bool IsThreeState
{ {
get => GetValue(IsThreeStateProperty); get => GetValue(IsThreeStateProperty);
@ -47,18 +109,78 @@ namespace Avalonia.Controls.Primitives
base.OnClick(); base.OnClick();
} }
/// <summary>
/// Toggles the <see cref="IsChecked"/> property.
/// </summary>
protected virtual void Toggle() protected virtual void Toggle()
{ {
if (IsChecked.HasValue) if (IsChecked.HasValue)
{
if (IsChecked.Value) if (IsChecked.Value)
{
if (IsThreeState) if (IsThreeState)
{
IsChecked = null; IsChecked = null;
}
else else
{
IsChecked = false; IsChecked = false;
}
}
else else
{
IsChecked = true; IsChecked = true;
}
}
else else
{
IsChecked = false; IsChecked = false;
}
}
/// <summary>
/// Called when <see cref="IsChecked"/> becomes true.
/// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
protected virtual void OnChecked(RoutedEventArgs e)
{
RaiseEvent(e);
}
/// <summary>
/// Called when <see cref="IsChecked"/> becomes false.
/// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
protected virtual void OnUnchecked(RoutedEventArgs e)
{
RaiseEvent(e);
}
/// <summary>
/// Called when <see cref="IsChecked"/> becomes null.
/// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
protected virtual void OnIndeterminate(RoutedEventArgs e)
{
RaiseEvent(e);
}
private void OnIsCheckedChanged(AvaloniaPropertyChangedEventArgs e)
{
var newValue = (bool?)e.NewValue;
switch (newValue)
{
case true:
OnChecked(new RoutedEventArgs(CheckedEvent));
break;
case false:
OnUnchecked(new RoutedEventArgs(UncheckedEvent));
break;
default:
OnIndeterminate(new RoutedEventArgs(IndeterminateEvent));
break;
}
} }
} }
} }

54
tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs

@ -1,5 +1,4 @@
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Markup.Data;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Xunit; using Xunit;
@ -63,6 +62,54 @@ namespace Avalonia.Controls.Primitives.UnitTests
Assert.Null(threeStateButton.IsChecked); Assert.Null(threeStateButton.IsChecked);
} }
[Fact]
public void ToggleButton_Events_Are_Raised_On_Is_Checked_Changes()
{
var threeStateButton = new ToggleButton();
bool checkedRaised = false;
threeStateButton.Checked += (_, __) => checkedRaised = true;
threeStateButton.IsChecked = true;
Assert.True(checkedRaised);
bool uncheckedRaised = false;
threeStateButton.Unchecked += (_, __) => uncheckedRaised = true;
threeStateButton.IsChecked = false;
Assert.True(uncheckedRaised);
bool indeterminateRaised = false;
threeStateButton.Indeterminate += (_, __) => indeterminateRaised = true;
threeStateButton.IsChecked = null;
Assert.True(indeterminateRaised);
}
[Fact]
public void ToggleButton_Events_Are_Raised_When_Toggling()
{
var threeStateButton = new TestToggleButton { IsThreeState = true };
bool checkedRaised = false;
threeStateButton.Checked += (_, __) => checkedRaised = true;
threeStateButton.Toggle();
Assert.True(checkedRaised);
bool indeterminateRaised = false;
threeStateButton.Indeterminate += (_, __) => indeterminateRaised = true;
threeStateButton.Toggle();
Assert.True(indeterminateRaised);
bool uncheckedRaised = false;
threeStateButton.Unchecked += (_, __) => uncheckedRaised = true;
threeStateButton.Toggle();
Assert.True(uncheckedRaised);
}
private class Class1 : NotifyingBase private class Class1 : NotifyingBase
{ {
private bool _foo; private bool _foo;
@ -80,5 +127,10 @@ namespace Avalonia.Controls.Primitives.UnitTests
set { nullableFoo = value; RaisePropertyChanged(); } set { nullableFoo = value; RaisePropertyChanged(); }
} }
} }
private class TestToggleButton : ToggleButton
{
public new void Toggle() => base.Toggle();
}
} }
} }

Loading…
Cancel
Save