From 35f26081c6d84afd2ed3d85ee6d2ea705367de71 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 9 Jan 2020 22:27:56 +0100 Subject: [PATCH] Implement events for ToggleButton. --- .../Primitives/ToggleButton.cs | 122 ++++++++++++++++++ .../Primitives/ToggleButtonTests.cs | 54 +++++++- 2 files changed, 175 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/ToggleButton.cs b/src/Avalonia.Controls/Primitives/ToggleButton.cs index e7cd0697a0..247e55a347 100644 --- a/src/Avalonia.Controls/Primitives/ToggleButton.cs +++ b/src/Avalonia.Controls/Primitives/ToggleButton.cs @@ -7,8 +7,14 @@ using Avalonia.Data; namespace Avalonia.Controls.Primitives { + /// + /// Represents a control that a user can select (check) or clear (uncheck). Base class for controls that can switch states. + /// public class ToggleButton : Button { + /// + /// Defines the property. + /// public static readonly DirectProperty IsCheckedProperty = AvaloniaProperty.RegisterDirect( nameof(IsChecked), @@ -17,9 +23,30 @@ namespace Avalonia.Controls.Primitives unsetValue: null, defaultBindingMode: BindingMode.TwoWay); + /// + /// Defines the property. + /// public static readonly StyledProperty IsThreeStateProperty = AvaloniaProperty.Register(nameof(IsThreeState)); + /// + /// Defines the event. + /// + public static readonly RoutedEvent CheckedEvent = + RoutedEvent.Register(nameof(Checked), RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent UncheckedEvent = + RoutedEvent.Register(nameof(Unchecked), RoutingStrategies.Bubble); + + /// + /// Defines the event. + /// + public static readonly RoutedEvent IndeterminateEvent = + RoutedEvent.Register(nameof(Indeterminate), RoutingStrategies.Bubble); + private bool? _isChecked = false; static ToggleButton() @@ -27,14 +54,49 @@ namespace Avalonia.Controls.Primitives PseudoClass(IsCheckedProperty, c => c == true, ":checked"); PseudoClass(IsCheckedProperty, c => c == false, ":unchecked"); PseudoClass(IsCheckedProperty, c => c == null, ":indeterminate"); + + IsCheckedProperty.Changed.AddClassHandler((x, e) => x.OnIsCheckedChanged(e)); + } + + /// + /// Raised when a is checked. + /// + public event EventHandler Checked + { + add { AddHandler(CheckedEvent, value); } + remove { RemoveHandler(CheckedEvent, value); } + } + + /// + /// Raised when a is unchecked. + /// + public event EventHandler Unchecked + { + add { AddHandler(UncheckedEvent, value); } + remove { RemoveHandler(UncheckedEvent, value); } + } + + /// + /// Raised when a is neither checked nor unchecked. + /// + public event EventHandler Indeterminate + { + add { AddHandler(IndeterminateEvent, value); } + remove { RemoveHandler(IndeterminateEvent, value); } } + /// + /// Gets or sets whether the is checked. + /// public bool? IsChecked { get { return _isChecked; } set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); } } + /// + /// Gets or sets a value that indicates whether the control supports three states. + /// public bool IsThreeState { get => GetValue(IsThreeStateProperty); @@ -47,18 +109,78 @@ namespace Avalonia.Controls.Primitives base.OnClick(); } + /// + /// Toggles the property. + /// protected virtual void Toggle() { if (IsChecked.HasValue) + { if (IsChecked.Value) + { if (IsThreeState) + { IsChecked = null; + } else + { IsChecked = false; + } + } else + { IsChecked = true; + } + } else + { IsChecked = false; + } + } + + /// + /// Called when becomes true. + /// + /// Event arguments for the routed event that is raised by the default implementation of this method. + protected virtual void OnChecked(RoutedEventArgs e) + { + RaiseEvent(e); + } + + /// + /// Called when becomes false. + /// + /// Event arguments for the routed event that is raised by the default implementation of this method. + protected virtual void OnUnchecked(RoutedEventArgs e) + { + RaiseEvent(e); + } + + /// + /// Called when becomes null. + /// + /// Event arguments for the routed event that is raised by the default implementation of this method. + 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; + } } } } diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs index 4f4ab47b0a..9acd42aba6 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs @@ -1,5 +1,4 @@ using Avalonia.Data; -using Avalonia.Markup.Data; using Avalonia.UnitTests; using Xunit; @@ -63,6 +62,54 @@ namespace Avalonia.Controls.Primitives.UnitTests 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 bool _foo; @@ -80,5 +127,10 @@ namespace Avalonia.Controls.Primitives.UnitTests set { nullableFoo = value; RaisePropertyChanged(); } } } + + private class TestToggleButton : ToggleButton + { + public new void Toggle() => base.Toggle(); + } } }