From 564d76ef7c53edea5488b76b890774bd9d4346c9 Mon Sep 17 00:00:00 2001 From: Corvin <43533385+corvinsz@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:01:13 +0200 Subject: [PATCH 1/7] feat: add MinuteSelectionStep property to Clock adds a new property called MinuteSelectionStep to the Clock so consumers can control the interval/step of the minutes --- src/MaterialDesignThemes.Wpf/Clock.cs | 57 ++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src/MaterialDesignThemes.Wpf/Clock.cs b/src/MaterialDesignThemes.Wpf/Clock.cs index 6217033d3c..12cf7aab44 100644 --- a/src/MaterialDesignThemes.Wpf/Clock.cs +++ b/src/MaterialDesignThemes.Wpf/Clock.cs @@ -237,6 +237,30 @@ public CornerRadius CornerRadius set => SetValue(CornerRadiusProperty, value); } + public static readonly DependencyProperty MinuteSelectionStepProperty = DependencyProperty.Register( + nameof(MinuteSelectionStep), typeof(int),typeof(Clock), new PropertyMetadata(1, MinuteSelectionStepPropertyChangedCallback)); + + private static void MinuteSelectionStepPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var clock = (Clock)d; + + int step = (int)e.NewValue; + + if (step < 1 || step > 60 || 60 % step != 0) + throw new ArgumentOutOfRangeException( + nameof(MinuteSelectionStep), + "MinuteSelectionStep must be a divisor of 60 and between 1 and 60."); + + clock.GenerateButtons(); + } + + public int MinuteSelectionStep + { + get => (int)GetValue(MinuteSelectionStepProperty); + set => SetValue(MinuteSelectionStepProperty, value); + } + + public static readonly RoutedEvent ClockChoiceMadeEvent = EventManager.RegisterRoutedEvent( "ClockChoiceMade", @@ -317,10 +341,17 @@ private void GenerateButtons() { RemoveExistingButtons(minutesCanvas); - GenerateButtons(minutesCanvas, Enumerable.Range(1, 60).ToList(), ButtonRadiusRatio, + GenerateButtons( + minutesCanvas, + Enumerable.Range(1, 60).ToList(), + ButtonRadiusRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Minutes, Is24Hours), - i => ((i / 5.0) % 1) == 0.0 ? "ButtonStyle" : "LesserButtonStyle", "0", - ClockDisplayMode.Minutes); + i => ((i / 5.0) % 1) == 0.0 + ? "ButtonStyle" + : "LesserButtonStyle", + "0", + ClockDisplayMode.Minutes, + i => (i % 60) % MinuteSelectionStep == 0); } if (GetTemplateChild(SecondsCanvasPartName) is Canvas secondsCanvas) @@ -361,7 +392,8 @@ private void GenerateButtons( IValueConverter isCheckedConverter, Func stylePropertySelector, string format, - ClockDisplayMode clockDisplayMode) + ClockDisplayMode clockDisplayMode, + Func? isEnabledSelector = null) { var anglePerItem = 360.0 / range.Count; var radiansPerItem = anglePerItem * (Math.PI / 180); @@ -388,6 +420,16 @@ private void GenerateButtons( button.SetBinding(Canvas.TopProperty, GetBinding("Y", button)); button.Content = (i == 60 ? 0 : (i == 24 && clockDisplayMode == ClockDisplayMode.Hours ? 0 : i)).ToString(format); + + if (isEnabledSelector is not null) + { + bool isEnabled = isEnabledSelector.Invoke(i); + button.IsEnabled = isEnabled; + if (!isEnabled) + { + button.Opacity = 0.38; + } + } canvas.Children.Add(button); } @@ -476,7 +518,12 @@ private void ClockItemDragDeltaHandler(object sender, DragDeltaEventArgs dragDel } else { - var value = (int)Math.Round(30 * angle / Math.PI, MidpointRounding.AwayFromZero) % 60; + int rawValue = (int)Math.Round(30 * angle / Math.PI, MidpointRounding.AwayFromZero) % 60; + + int value = DisplayMode == ClockDisplayMode.Minutes + ? ((int)Math.Round(rawValue / (double)MinuteSelectionStep, MidpointRounding.AwayFromZero) + * MinuteSelectionStep) % 60 + : rawValue; if (DisplayMode == ClockDisplayMode.Minutes) time = new DateTime(Time.Year, Time.Month, Time.Day, Time.Hour, value, Time.Second); else From 3b6eab0932659dcad6f56705c55dbd3729e21a84 Mon Sep 17 00:00:00 2001 From: Corvin <43533385+corvinsz@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:01:40 +0200 Subject: [PATCH 2/7] test(clock): ensure correct MinuteSelectionStep behavior --- .../ClockTests.cs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs index 98a4237445..4530002056 100644 --- a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs +++ b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs @@ -82,4 +82,77 @@ void OnTimeChanged(object? sender, TimeChangedEventArgs e) await Assert.That(invocations[1].OldTime).IsEqualTo(now); await Assert.That(invocations[1].NewTime).IsEqualTo(now + TimeSpan.FromMinutes(-2)); } + + + [Test] + [Arguments(1)] + [Arguments(2)] + [Arguments(3)] + [Arguments(4)] + [Arguments(5)] + [Arguments(6)] + [Arguments(10)] + [Arguments(12)] + [Arguments(15)] + [Arguments(20)] + [Arguments(30)] + [Arguments(60)] + public async Task MinuteSelectionStep_WhenSet_OnlyMatchingMinuteButtonsAreEnabled(int minuteSelectionStep) + { + var clock = new Clock + { + MinuteSelectionStep = minuteSelectionStep + }; + + clock.ApplyDefaultStyle(); + + Canvas minutesCanvas = clock.FindVisualChild(Clock.MinutesCanvasPartName); + var minuteButtons = minutesCanvas.GetVisualChildren(); + + foreach (var button in minuteButtons) + { + int value = int.Parse(button.Content!.ToString()!); + + bool shouldBeEnabled = value % minuteSelectionStep == 0; + + await Assert.That(button.IsEnabled).IsEqualTo(shouldBeEnabled); + await Assert.That(button.Opacity).IsEqualTo(shouldBeEnabled ? 1d : 0.38d); + } + } + + [Test] + public async Task MinuteSelectionStep_Default_AllButtonsAreEnabled() + { + var clock = new Clock(); + + clock.ApplyDefaultStyle(); + + Canvas minutesCanvas = clock.FindVisualChild(Clock.MinutesCanvasPartName); + var minuteButtons = minutesCanvas.GetVisualChildren(); + + await Assert.That(minuteButtons.All(x => x.IsEnabled)).IsTrue(); + } + + [Test] + public async Task MinuteSelectionStep_DefaultValue_IsOne() + { + var clock = new Clock(); + + await Assert.That(clock.MinuteSelectionStep).IsEqualTo(1); + } + + [Test] + [Arguments(0)] + [Arguments(-1)] + [Arguments(61)] + [Arguments(7)] + [Arguments(13)] + [Arguments(59)] + public async Task MinuteSelectionStep_InvalidValues_Throws(int value) + { + var clock = new Clock(); + + await Assert.That(() => clock.MinuteSelectionStep = value) + .Throws(); + } } From caffc88c442491cbb557a54b8ece60ff73a42df0 Mon Sep 17 00:00:00 2001 From: Corvin <43533385+corvinsz@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:54:12 +0200 Subject: [PATCH 3/7] test: correctly assert MinuteSelectionStep throws on invalid values --- tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs index 4530002056..9669aff9d1 100644 --- a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs +++ b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs @@ -152,7 +152,8 @@ public async Task MinuteSelectionStep_InvalidValues_Throws(int value) { var clock = new Clock(); - await Assert.That(() => clock.MinuteSelectionStep = value) - .Throws(); + var ex = Assert.Throws(() => clock.MinuteSelectionStep = value); + + await Assert.That(ex.Message).IsEqualTo($"{nameof(Clock.MinuteSelectionStep)} must be a divisor of 60 and between 1 and 60. (Parameter '{nameof(Clock.MinuteSelectionStep)}')"); } } From b0c8e8f81b1413e55fa402ba2deed8d572f792af Mon Sep 17 00:00:00 2001 From: Corvin <43533385+corvinsz@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:18:22 +0200 Subject: [PATCH 4/7] docs: add MinuteSelectionStep example to MD2/3 demo apps and consolidate viewmodels --- src/MainDemo.Wpf/Domain/PickersViewModel.cs | 41 --- src/MainDemo.Wpf/Pickers.xaml | 255 ++++++++---------- .../Domain/PickersViewModel.cs | 41 --- src/MaterialDesign3.Demo.Wpf/Pickers.xaml | 34 ++- src/MaterialDesign3.Demo.Wpf/Pickers.xaml.cs | 2 +- .../Domain/PickersViewModel.cs | 29 ++ 6 files changed, 166 insertions(+), 236 deletions(-) delete mode 100644 src/MainDemo.Wpf/Domain/PickersViewModel.cs delete mode 100644 src/MaterialDesign3.Demo.Wpf/Domain/PickersViewModel.cs create mode 100644 src/MaterialDesignDemo.Shared/Domain/PickersViewModel.cs diff --git a/src/MainDemo.Wpf/Domain/PickersViewModel.cs b/src/MainDemo.Wpf/Domain/PickersViewModel.cs deleted file mode 100644 index 1a8c480f47..0000000000 --- a/src/MainDemo.Wpf/Domain/PickersViewModel.cs +++ /dev/null @@ -1,41 +0,0 @@ -using MaterialDesignDemo.Shared.Domain; - -namespace MaterialDesignDemo.Domain; - -public class PickersViewModel : ViewModelBase -{ - private DateTime _date; - private DateTime _time; - private string? _validatingTime; - private DateTime? _futureValidatingDate; - - public PickersViewModel() - { - Date = DateTime.Now; - Time = DateTime.Now; - } - - public DateTime Date - { - get => _date; - set => SetProperty(ref _date, value); - } - - public DateTime Time - { - get => _time; - set => SetProperty(ref _time, value); - } - - public string? ValidatingTime - { - get => _validatingTime; - set => SetProperty(ref _validatingTime, value); - } - - public DateTime? FutureValidatingDate - { - get => _futureValidatingDate; - set => SetProperty(ref _futureValidatingDate, value); - } -} diff --git a/src/MainDemo.Wpf/Pickers.xaml b/src/MainDemo.Wpf/Pickers.xaml index 18deca9fb8..86979d9100 100644 --- a/src/MainDemo.Wpf/Pickers.xaml +++ b/src/MainDemo.Wpf/Pickers.xaml @@ -12,8 +12,7 @@ d:DesignWidth="1920" mc:Ignorable="d"> - + @@ -31,45 +30,32 @@ - + - @@ -83,8 +69,7 @@ materialDesign:CalendarAssist.IsHeaderVisible="False" materialDesign:HintAssist.Hint="Future Date"> - + @@ -104,8 +89,7 @@ - + @@ -174,9 +158,9 @@ HorizontalAlignment="Left" UniqueKey="pickers_unchanging_borderthickness"> @@ -184,10 +168,10 @@ HorizontalAlignment="Left" UniqueKey="pickers_14_custom_borderthickness"> @@ -216,41 +200,38 @@ + HorizontalAlignment="Left" + VerticalAlignment="Top" + UniqueKey="pickers_7"> + Width="100" + Is24Hours="True" + SelectedTimeChanged="PresetTimePicker_SelectedTimeChanged" /> - + HorizontalAlignment="Left" + VerticalAlignment="Top" + UniqueKey="pickers_15"> + - - - + + + - + @@ -280,12 +261,11 @@ - + - + - - + + @@ -355,8 +333,7 @@ - + - - + + - + - - + + - - + + + Foreground="{DynamicResource PrimaryHueLightForegroundBrush}" + IsEnabled="{Binding DataContext.ControlsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" /> - - + + + Foreground="White" + IsEnabled="{Binding DataContext.ControlsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" /> - - + + - + - - + + @@ -534,13 +495,11 @@ - + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + - + - - - + + + - - + + - - + + - - + + - - + + - - + + _date; - set => SetProperty(ref _date, value); - } - - public DateTime Time - { - get => _time; - set => SetProperty(ref _time, value); - } - - public string? ValidatingTime - { - get => _validatingTime; - set => SetProperty(ref _validatingTime, value); - } - - public DateTime? FutureValidatingDate - { - get => _futureValidatingDate; - set => SetProperty(ref _futureValidatingDate, value); - } -} diff --git a/src/MaterialDesign3.Demo.Wpf/Pickers.xaml b/src/MaterialDesign3.Demo.Wpf/Pickers.xaml index f38eb0ef0f..186a5b74dd 100644 --- a/src/MaterialDesign3.Demo.Wpf/Pickers.xaml +++ b/src/MaterialDesign3.Demo.Wpf/Pickers.xaml @@ -407,11 +407,11 @@ + Foreground="{DynamicResource MaterialDesign.Brush.Primary.Light.Foreground}" + IsEnabled="{Binding DataContext.ControlsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" /> @@ -439,11 +439,11 @@ + Foreground="White" + IsEnabled="{Binding DataContext.ControlsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" /> @@ -468,8 +468,8 @@ Style="{StaticResource MaterialDesignCardGroupBox}"> + IsEnabled="{Binding DataContext.ControlsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" + Style="{StaticResource MaterialDesignCalendarPortraitForeground}" /> @@ -559,6 +559,26 @@ + + + + + + + + + + @@ -650,6 +670,8 @@ + + diff --git a/src/MaterialDesign3.Demo.Wpf/Pickers.xaml.cs b/src/MaterialDesign3.Demo.Wpf/Pickers.xaml.cs index a6658499a6..54e488cf57 100644 --- a/src/MaterialDesign3.Demo.Wpf/Pickers.xaml.cs +++ b/src/MaterialDesign3.Demo.Wpf/Pickers.xaml.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using System.Globalization; -using MaterialDesign3Demo.Domain; +using MaterialDesignDemo.Domain; using MaterialDesignThemes.Wpf; namespace MaterialDesign3Demo; diff --git a/src/MaterialDesignDemo.Shared/Domain/PickersViewModel.cs b/src/MaterialDesignDemo.Shared/Domain/PickersViewModel.cs new file mode 100644 index 0000000000..cc41371687 --- /dev/null +++ b/src/MaterialDesignDemo.Shared/Domain/PickersViewModel.cs @@ -0,0 +1,29 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace MaterialDesignDemo.Domain; + +public partial class PickersViewModel : ObservableObject +{ + [ObservableProperty] + private DateTime _date; + [ObservableProperty] + private DateTime _time; + [ObservableProperty] + private string? _validatingTime; + [ObservableProperty] + private DateTime? _futureValidatingDate; + + public IReadOnlyList AvailableMinuteSelectionSteps { get; } + + [ObservableProperty] + private int _selectedMinuteSelectionStep; + + public PickersViewModel() + { + Date = DateTime.Now; + Time = DateTime.Now; + + AvailableMinuteSelectionSteps = [ 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ]; + SelectedMinuteSelectionStep = 15; + } +} From 90799288b178e0fafaab824cc76e229cccb8cfe0 Mon Sep 17 00:00:00 2001 From: Corvin <43533385+corvinsz@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:21:51 +0200 Subject: [PATCH 5/7] refactor: use nameof keyword --- src/MaterialDesignThemes.Wpf/Clock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MaterialDesignThemes.Wpf/Clock.cs b/src/MaterialDesignThemes.Wpf/Clock.cs index 12cf7aab44..76bc200961 100644 --- a/src/MaterialDesignThemes.Wpf/Clock.cs +++ b/src/MaterialDesignThemes.Wpf/Clock.cs @@ -249,7 +249,7 @@ private static void MinuteSelectionStepPropertyChangedCallback(DependencyObject if (step < 1 || step > 60 || 60 % step != 0) throw new ArgumentOutOfRangeException( nameof(MinuteSelectionStep), - "MinuteSelectionStep must be a divisor of 60 and between 1 and 60."); + $"{nameof(MinuteSelectionStep)} must be a divisor of 60 and between 1 and 60."); clock.GenerateButtons(); } From 62aacf76a9c033b1d8bd172766f339e84d932462 Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Thu, 30 Apr 2026 22:42:17 -0700 Subject: [PATCH 6/7] ``` refactor: move disabled clock button styling to XAML This change consolidates the visual styling for disabled clock buttons into the XAML. Moving the opacity setting from code-behind to the control's style improves the separation of concerns. Additionally, updates button collection generation to use C# 12 collection expressions for improved conciseness. ``` --- src/MaterialDesignThemes.Wpf/Clock.cs | 17 ++++++----------- .../Themes/MaterialDesignTheme.Clock.xaml | 3 +++ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/MaterialDesignThemes.Wpf/Clock.cs b/src/MaterialDesignThemes.Wpf/Clock.cs index 76bc200961..ce0cf2ca3f 100644 --- a/src/MaterialDesignThemes.Wpf/Clock.cs +++ b/src/MaterialDesignThemes.Wpf/Clock.cs @@ -260,7 +260,6 @@ public int MinuteSelectionStep set => SetValue(MinuteSelectionStepProperty, value); } - public static readonly RoutedEvent ClockChoiceMadeEvent = EventManager.RegisterRoutedEvent( "ClockChoiceMade", @@ -324,15 +323,15 @@ private void GenerateButtons() if (Is24Hours) { - GenerateButtons(hoursCanvas, Enumerable.Range(13, 12).ToList(), ButtonRadiusRatio, + GenerateButtons(hoursCanvas, [.. Enumerable.Range(13, 12)], ButtonRadiusRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Hours, Is24Hours), i => "ButtonStyle", "00", ClockDisplayMode.Hours); - GenerateButtons(hoursCanvas, Enumerable.Range(1, 12).ToList(), ButtonRadiusInnerRatio, + GenerateButtons(hoursCanvas, [.. Enumerable.Range(1, 12)], ButtonRadiusInnerRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Hours, Is24Hours), i => "ButtonStyle", "#", ClockDisplayMode.Hours); } else - GenerateButtons(hoursCanvas, Enumerable.Range(1, 12).ToList(), ButtonRadiusRatio, + GenerateButtons(hoursCanvas, [.. Enumerable.Range(1, 12)], ButtonRadiusRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Hours, Is24Hours), i => "ButtonStyle", "0", ClockDisplayMode.Hours); } @@ -343,7 +342,7 @@ private void GenerateButtons() GenerateButtons( minutesCanvas, - Enumerable.Range(1, 60).ToList(), + [.. Enumerable.Range(1, 60)], ButtonRadiusRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Minutes, Is24Hours), i => ((i / 5.0) % 1) == 0.0 @@ -358,7 +357,7 @@ private void GenerateButtons() { RemoveExistingButtons(secondsCanvas); - GenerateButtons(secondsCanvas, Enumerable.Range(1, 60).ToList(), ButtonRadiusRatio, + GenerateButtons(secondsCanvas, [.. Enumerable.Range(1, 60)], ButtonRadiusRatio, new ClockItemIsCheckedConverter(() => Time, ClockDisplayMode.Seconds, Is24Hours), i => ((i / 5.0) % 1) == 0.0 ? "ButtonStyle" : "LesserButtonStyle", "0", ClockDisplayMode.Seconds); @@ -387,7 +386,7 @@ private void HourReadOutPartNameOnPreviewMouseLeftButtonDown(object sender, Mous private void GenerateButtons( Panel canvas, - ICollection range, + List range, double radiusRatio, IValueConverter isCheckedConverter, Func stylePropertySelector, @@ -425,10 +424,6 @@ private void GenerateButtons( { bool isEnabled = isEnabledSelector.Invoke(i); button.IsEnabled = isEnabled; - if (!isEnabled) - { - button.Opacity = 0.38; - } } canvas.Children.Add(button); } diff --git a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Clock.xaml b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Clock.xaml index 116583e896..2256a873cf 100644 --- a/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Clock.xaml +++ b/src/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Clock.xaml @@ -126,6 +126,9 @@ + + + From b236d8dbd04285851ca688d1c122b9c2c434922e Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Thu, 30 Apr 2026 23:18:58 -0700 Subject: [PATCH 7/7] test(clock): remove outdated `MinuteSelectionStep` button enablement tests These tests verified the enabled state and opacity of minute selection buttons based on the `MinuteSelectionStep` property. Following the refactor that moved disabled clock button styling to XAML, these tests are no longer relevant to code-behind logic. --- .../ClockTests.cs | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs index 9669aff9d1..88ca80992d 100644 --- a/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs +++ b/tests/MaterialDesignThemes.Wpf.Tests/ClockTests.cs @@ -83,56 +83,6 @@ void OnTimeChanged(object? sender, TimeChangedEventArgs e) await Assert.That(invocations[1].NewTime).IsEqualTo(now + TimeSpan.FromMinutes(-2)); } - - [Test] - [Arguments(1)] - [Arguments(2)] - [Arguments(3)] - [Arguments(4)] - [Arguments(5)] - [Arguments(6)] - [Arguments(10)] - [Arguments(12)] - [Arguments(15)] - [Arguments(20)] - [Arguments(30)] - [Arguments(60)] - public async Task MinuteSelectionStep_WhenSet_OnlyMatchingMinuteButtonsAreEnabled(int minuteSelectionStep) - { - var clock = new Clock - { - MinuteSelectionStep = minuteSelectionStep - }; - - clock.ApplyDefaultStyle(); - - Canvas minutesCanvas = clock.FindVisualChild(Clock.MinutesCanvasPartName); - var minuteButtons = minutesCanvas.GetVisualChildren(); - - foreach (var button in minuteButtons) - { - int value = int.Parse(button.Content!.ToString()!); - - bool shouldBeEnabled = value % minuteSelectionStep == 0; - - await Assert.That(button.IsEnabled).IsEqualTo(shouldBeEnabled); - await Assert.That(button.Opacity).IsEqualTo(shouldBeEnabled ? 1d : 0.38d); - } - } - - [Test] - public async Task MinuteSelectionStep_Default_AllButtonsAreEnabled() - { - var clock = new Clock(); - - clock.ApplyDefaultStyle(); - - Canvas minutesCanvas = clock.FindVisualChild(Clock.MinutesCanvasPartName); - var minuteButtons = minutesCanvas.GetVisualChildren(); - - await Assert.That(minuteButtons.All(x => x.IsEnabled)).IsTrue(); - } - [Test] public async Task MinuteSelectionStep_DefaultValue_IsOne() {