diff --git a/DesktopClock/DesktopClock.csproj b/DesktopClock/DesktopClock.csproj index 371a868..0849cf6 100644 --- a/DesktopClock/DesktopClock.csproj +++ b/DesktopClock/DesktopClock.csproj @@ -17,7 +17,6 @@ - diff --git a/DesktopClock/MainWindow.xaml.cs b/DesktopClock/MainWindow.xaml.cs index ebeaa81..271b080 100644 --- a/DesktopClock/MainWindow.xaml.cs +++ b/DesktopClock/MainWindow.xaml.cs @@ -9,8 +9,6 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using DesktopClock.Properties; using DesktopClock.Utilities; using H.NotifyIcon; @@ -22,8 +20,7 @@ namespace DesktopClock; /// /// Interaction logic for MainWindow.xaml /// -[ObservableObject] -public partial class MainWindow : Window +public partial class MainWindow : Window, INotifyPropertyChanged { private readonly SystemClockTimer _systemClockTimer; private TaskbarIcon _trayIcon; @@ -38,14 +35,32 @@ public partial class MainWindow : Window private DesktopPinner _desktopPinner; private readonly WheelNotches _wheelNotches = new(); +#pragma warning disable CS0067 // The event 'MainWindow.PropertyChanged' is never used. Handled by Fody. + public event PropertyChangedEventHandler PropertyChanged; +#pragma warning restore CS0067 + /// /// The current date and time in the selected time zone, or the formatted countdown text. /// - [ObservableProperty] - private string _currentTimeOrCountdownString; + public string CurrentTimeOrCountdownString { get; set; } + + // The menu shared by the clock and the tray icon binds to these. + public ICommand CopyToClipboardCommand { get; } + public ICommand HideForNowCommand { get; } + public ICommand OpenSettingsWindowCommand { get; } + public ICommand OpenReleasesPageCommand { get; } + public ICommand OpenIssueTrackerCommand { get; } + public ICommand ExitCommand { get; } public MainWindow() { + CopyToClipboardCommand = new RelayCommand(CopyToClipboard); + HideForNowCommand = new RelayCommand(HideForNow); + OpenSettingsWindowCommand = new RelayCommand(OpenSettingsWindow); + OpenReleasesPageCommand = new RelayCommand(OpenReleasesPage); + OpenIssueTrackerCommand = new RelayCommand(OpenIssueTracker); + ExitCommand = new RelayCommand(Exit); + InitializeComponent(); DataContext = this; @@ -144,7 +159,6 @@ private void ThemeManager_ThemeChanged(object sender, EventArgs e) /// /// Copies the current time string to the clipboard. /// - [RelayCommand] public void CopyToClipboard() { try @@ -160,7 +174,6 @@ public void CopyToClipboard() /// /// Minimizes the window. /// - [RelayCommand] public void HideForNow() { this.HideFromScreen(); @@ -195,19 +208,16 @@ public void ShowClockAndSettings() /// /// Opens a new settings window or activates the existing one. /// - [RelayCommand] public void OpenSettingsWindow() { App.ShowSingletonWindow(); } - [RelayCommand] public void OpenReleasesPage() { OpenUrl("https://github.com/danielchalmers/DesktopClock/releases"); } - [RelayCommand] public void OpenIssueTracker() { OpenUrl("https://github.com/danielchalmers/DesktopClock/issues"); @@ -216,7 +226,6 @@ public void OpenIssueTracker() /// /// Closes the app. /// - [RelayCommand] public void Exit() { Application.Current.Shutdown(); diff --git a/DesktopClock/SettingsWindow.xaml b/DesktopClock/SettingsWindow.xaml index bf902f5..9da1e29 100644 --- a/DesktopClock/SettingsWindow.xaml +++ b/DesktopClock/SettingsWindow.xaml @@ -671,12 +671,6 @@ Style="{StaticResource CardGroupBox}"> - - - CommunityToolkit - - diff --git a/DesktopClock/SettingsWindow.xaml.cs b/DesktopClock/SettingsWindow.xaml.cs index d9b8d08..b972ed5 100644 --- a/DesktopClock/SettingsWindow.xaml.cs +++ b/DesktopClock/SettingsWindow.xaml.cs @@ -9,10 +9,9 @@ using System.Windows; using System.Windows.Automation; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Media; using System.Windows.Navigation; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using DesktopClock.Properties; using Microsoft.Win32; @@ -335,8 +334,13 @@ public static class NavButton public static void SetIsActive(DependencyObject obj, bool value) => obj.SetValue(IsActiveProperty, value); } -public partial class SettingsWindowViewModel : ObservableObject +public sealed class SettingsWindowViewModel : INotifyPropertyChanged { + // Nothing here changes after it's created, but bindings to an object without this event fall back to PropertyDescriptor change tracking, which is slower and can keep the object alive after the window closes. +#pragma warning disable CS0067 // The event 'SettingsWindowViewModel.PropertyChanged' is never used. + public event PropertyChangedEventHandler PropertyChanged; +#pragma warning restore CS0067 + // Enumerating fonts and time zones costs ~100 ms and the results don't change within a session, so they're fetched once on a background thread that the app kicks off while idle after startup. private static readonly Lazy Fonts, IList TimeZones)>> _systemLists = new(() => Task.Run(() => ( @@ -350,9 +354,16 @@ public partial class SettingsWindowViewModel : ObservableObject /// public string AppVersion { get; } + public ICommand ResetWavFilePathCommand { get; } + public ICommand ResetWavFileIntervalCommand { get; } + public ICommand ResetBackgroundImagePathCommand { get; } + public SettingsWindowViewModel(Settings settings) { Settings = settings; + ResetWavFilePathCommand = new RelayCommand(ResetWavFilePath); + ResetWavFileIntervalCommand = new RelayCommand(ResetWavFileInterval); + ResetBackgroundImagePathCommand = new RelayCommand(ResetBackgroundImagePath); AppVersion = FileVersionInfo.GetVersionInfo(App.MainFileInfo.FullName).FileVersion; FontStyles = [ @@ -450,7 +461,6 @@ public IList FontFamilies /// /// Clears the chime sound file path. /// - [RelayCommand] public void ResetWavFilePath() { Settings.WavFilePath = string.Empty; @@ -459,7 +469,6 @@ public void ResetWavFilePath() /// /// Resets the chime interval to the default value. /// - [RelayCommand] public void ResetWavFileInterval() { Settings.WavFileInterval = default; @@ -468,7 +477,6 @@ public void ResetWavFileInterval() /// /// Clears the background image path. /// - [RelayCommand] public void ResetBackgroundImagePath() { Settings.BackgroundImagePath = string.Empty; diff --git a/DesktopClock/Utilities/RelayCommand.cs b/DesktopClock/Utilities/RelayCommand.cs new file mode 100644 index 0000000..929ad45 --- /dev/null +++ b/DesktopClock/Utilities/RelayCommand.cs @@ -0,0 +1,17 @@ +using System; +using System.Windows.Input; + +namespace DesktopClock; + +/// +/// A command that runs an action, for binding menu items and buttons to methods. +/// +public sealed class RelayCommand(Action execute) : ICommand +{ + // The commands can always run, so there's never a change to report. + public event EventHandler CanExecuteChanged { add { } remove { } } + + public bool CanExecute(object parameter) => true; + + public void Execute(object parameter) => execute(); +}