diff --git a/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml new file mode 100644 index 00000000..5502a7c8 --- /dev/null +++ b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml.cs b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml.cs new file mode 100644 index 00000000..98528a99 --- /dev/null +++ b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/AuthenticationButtonView.xaml.cs @@ -0,0 +1,53 @@ +namespace Atc.Wpf.Sample.SamplesWpfControls.ButtonControls; + +public partial class AuthenticationButtonView +{ + public AuthenticationButtonView() + { + InitializeComponent(); + + DataContext = this; + } + + [DependencyProperty] + private bool isBusy; + + [DependencyProperty] + private bool isAuthenticated; + + [RelayCommand] + private async Task Login() + { + IsBusy = true; + + await Task + .Delay(2_000) + .ConfigureAwait(false); + + await Application.Current.Dispatcher + .InvokeAsyncIfRequired(() => + { + IsAuthenticated = true; + IsBusy = false; + }) + .ConfigureAwait(false); + } + + [RelayCommand] + private async Task Logout() + { + IsBusy = true; + + await Task + .Delay(500) + .ConfigureAwait(false); + + await Application.Current.Dispatcher + .InvokeAsyncIfRequired(() => + { + IsAuthenticated = false; + IsBusy = false; + }) + .ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml new file mode 100644 index 00000000..a23bc43b --- /dev/null +++ b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample/Atc.Wpf.Sample/SamplesWpfTheming/InputButton/ImageToggledButton.xaml.cs b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml.cs similarity index 87% rename from sample/Atc.Wpf.Sample/SamplesWpfTheming/InputButton/ImageToggledButton.xaml.cs rename to sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml.cs index 3274ca13..9ee3110e 100644 --- a/sample/Atc.Wpf.Sample/SamplesWpfTheming/InputButton/ImageToggledButton.xaml.cs +++ b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ConnectivityButtonView.xaml.cs @@ -1,8 +1,8 @@ -namespace Atc.Wpf.Sample.SamplesWpfTheming.InputButton; +namespace Atc.Wpf.Sample.SamplesWpfControls.ButtonControls; -public partial class ImageToggledButton +public partial class ConnectivityButtonView { - public ImageToggledButton() + public ConnectivityButtonView() { InitializeComponent(); diff --git a/sample/Atc.Wpf.Sample/SamplesWpfControls/BaseControls/ImageButtonView.xaml b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ImageButtonView.xaml similarity index 96% rename from sample/Atc.Wpf.Sample/SamplesWpfControls/BaseControls/ImageButtonView.xaml rename to sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ImageButtonView.xaml index d3347455..a6e2c83c 100644 --- a/sample/Atc.Wpf.Sample/SamplesWpfControls/BaseControls/ImageButtonView.xaml +++ b/sample/Atc.Wpf.Sample/SamplesWpfControls/ButtonControls/ImageButtonView.xaml @@ -1,5 +1,5 @@ + { + IsConnected = true; + IsBusy = false; + }) + .ConfigureAwait(false); + } + + [RelayCommand] + private async Task Disconnect() + { + IsBusy = true; + + await Task + .Delay(500) + .ConfigureAwait(false); + + await Application.Current.Dispatcher + .InvokeAsyncIfRequired(() => + { + IsConnected = false; + IsBusy = false; + }) + .ConfigureAwait(false); + } +} \ No newline at end of file diff --git a/sample/Atc.Wpf.Sample/SamplesWpfControlsTreeView.xaml b/sample/Atc.Wpf.Sample/SamplesWpfControlsTreeView.xaml index 1becbff4..f9eb96be 100644 --- a/sample/Atc.Wpf.Sample/SamplesWpfControlsTreeView.xaml +++ b/sample/Atc.Wpf.Sample/SamplesWpfControlsTreeView.xaml @@ -15,6 +15,7 @@ IsExpanded="True" SamplePath="DialogBoxes.StandardDialogBoxView" /> + - + + + + + + + - + net9.0-windows diff --git a/src/Atc.Wpf.Controls/BaseControls/ImageToggledButton.cs b/src/Atc.Wpf.Controls/BaseControls/ImageToggledButton.cs deleted file mode 100644 index f3a0fdce..00000000 --- a/src/Atc.Wpf.Controls/BaseControls/ImageToggledButton.cs +++ /dev/null @@ -1,132 +0,0 @@ -namespace Atc.Wpf.Controls.BaseControls; - -public sealed partial class ImageToggledButton : ImageButton -{ - [DependencyProperty( - DefaultValue = false, - PropertyChangedCallback = nameof(OnToggledChanged))] - private bool isToggled; - - [DependencyProperty] - private object? onContent; - - [DependencyProperty] - private object? offContent; - - [DependencyProperty] - private ImageSource? onImageSource; - - [DependencyProperty] - private ImageSource? offImageSource; - - [DependencyProperty(DefaultValue = "")] - private string onSvgImageSource; - - [DependencyProperty(DefaultValue = "")] - private string offSvgImageSource; - - [DependencyProperty] - private Color? onSvgImageOverrideColor; - - [DependencyProperty] - private Color? offSvgImageOverrideColor; - - [DependencyProperty] - private ICommand? onCommand; - - [DependencyProperty] - private ICommand? offCommand; - - static ImageToggledButton() - { - DefaultStyleKeyProperty.OverrideMetadata( - typeof(ImageToggledButton), - new FrameworkPropertyMetadata(typeof(ImageButton))); - } - - public ImageToggledButton() - { - // Initialise with the Off state visual when loaded. - Loaded += (_, _) => ApplyVisualState(IsToggled); - } - - protected override void OnClick() - { - base.OnClick(); - - IsToggled = !IsToggled; - - ExecuteCurrentCommand(); - } - - private static void OnToggledChanged( - DependencyObject d, - DependencyPropertyChangedEventArgs e) - { - var ctl = (ImageToggledButton)d; - ctl.ApplyVisualState((bool)e.NewValue); - } - - private void ApplyVisualState( - bool toggled) - { - if (toggled) - { - // ON state - if (OnContent is not null) - { - SetCurrentValue(ContentProperty, OnContent); - } - - if (OnImageSource is not null) - { - SetCurrentValue(ImageSourceProperty, OnImageSource); - } - - if (!string.IsNullOrEmpty(OnSvgImageSource)) - { - SetCurrentValue(SvgImageSourceProperty, OnSvgImageSource); - } - - if (OnSvgImageOverrideColor is not null) - { - SetCurrentValue(SvgImageOverrideColorProperty, OnSvgImageOverrideColor); - } - } - else - { - // OFF state - if (OffContent is not null) - { - SetCurrentValue(ContentProperty, OffContent); - } - - if (OffImageSource is not null) - { - SetCurrentValue(ImageSourceProperty, OffImageSource); - } - - if (!string.IsNullOrEmpty(OffSvgImageSource)) - { - SetCurrentValue(SvgImageSourceProperty, OffSvgImageSource); - } - - if (OffSvgImageOverrideColor is not null) - { - SetCurrentValue(SvgImageOverrideColorProperty, OffSvgImageOverrideColor); - } - } - } - - private void ExecuteCurrentCommand() - { - var cmd = IsToggled - ? OffCommand - : OnCommand; - - if (cmd?.CanExecute(parameter: null) == true) - { - cmd.Execute(parameter: null); - } - } -} \ No newline at end of file diff --git a/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml b/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml new file mode 100644 index 00000000..d746cbd4 --- /dev/null +++ b/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml @@ -0,0 +1,34 @@ + + + + + \ No newline at end of file diff --git a/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml.cs b/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml.cs new file mode 100644 index 00000000..03de49ed --- /dev/null +++ b/src/Atc.Wpf.Controls/ButtonControls/AuthenticationButton.xaml.cs @@ -0,0 +1,137 @@ +// ReSharper disable InvertIf +namespace Atc.Wpf.Controls.ButtonControls; + +public partial class AuthenticationButton +{ + public event RoutedEventHandler? IsAuthenticatedChanged; + + [DependencyProperty(DefaultValue = null)] + private ImageLocation? imageLocation; + + [DependencyProperty(DefaultValue = 16)] + private int imageWidth; + + [DependencyProperty(DefaultValue = 16)] + private int imageHeight; + + [DependencyProperty(DefaultValue = 10d)] + private double imageContentSpacing; + + [DependencyProperty(DefaultValue = 0d)] + private double imageBorderSpacing; + + [DependencyProperty(DefaultValue = false)] + private bool isBusy; + + [DependencyProperty( + DefaultValue = false, + PropertyChangedCallback = nameof(OnIsAuthenticatedChanged))] + private bool isAuthenticated; + + [DependencyProperty] + private object? loginContent; + + [DependencyProperty] + private object? logoutContent; + + [DependencyProperty] + private ImageSource? loginImageSource; + + [DependencyProperty] + private ImageSource? logoutImageSource; + + [DependencyProperty(DefaultValue = "")] + private string loginSvgImageSource; + + [DependencyProperty(DefaultValue = "")] + private string logoutSvgImageSource; + + [DependencyProperty] + private Color? loginSvgImageOverrideColor; + + [DependencyProperty] + private Color? logoutSvgImageOverrideColor; + + [DependencyProperty] + private ICommand? loginCommand; + + [DependencyProperty] + private ICommand? logoutCommand; + + public AuthenticationButton() + { + InitializeComponent(); + + SetCurrentValue(ImageLocationProperty, Controls.ImageLocation.Left); + + ThemeManager.Current.ThemeChanged += OnThemeChanged; + } + + protected override void OnInitialized( + EventArgs e) + { + base.OnInitialized(e); + + if (LoginContent is null or string { Length: 0 }) + { + SetCurrentValue(LoginContentProperty, Word.Login); + } + + if (LogoutContent is null or string { Length: 0 }) + { + SetCurrentValue(LogoutContentProperty, Word.Logout); + } + + if (LoginImageSource is null && + string.IsNullOrWhiteSpace(LoginSvgImageSource)) + { + var fgBrush = Application.Current.TryFindResource("AtcApps.Brushes.ThemeForeground"); + + var img = (ImageSource?)FontIconImageSourceValueConverter.Instance + .Convert( + FontMaterialDesignType.Login, + typeof(ImageSource), + fgBrush, + CultureInfo.CurrentUICulture); + + if (img is not null) + { + SetCurrentValue(LoginImageSourceProperty, img); + } + } + + if (LogoutImageSource is null && + string.IsNullOrWhiteSpace(LogoutSvgImageSource)) + { + var accentBrush = Application.Current.TryFindResource("AtcApps.Brushes.Accent"); + + var img = (ImageSource?)FontIconImageSourceValueConverter.Instance + .Convert( + FontMaterialDesignType.Logout, + typeof(ImageSource), + accentBrush, + CultureInfo.CurrentUICulture); + + if (img is not null) + { + SetCurrentValue(LogoutImageSourceProperty, img); + } + } + } + + private void OnThemeChanged( + object? sender, + ThemeChangedEventArgs e) + { + SetCurrentValue(LoginContentProperty, Word.Login); + SetCurrentValue(LogoutContentProperty, Word.Logout); + } + + private static void OnIsAuthenticatedChanged( + DependencyObject d, + DependencyPropertyChangedEventArgs e) + => ((AuthenticationButton)d).RaiseIsAuthenticatedChanged(); + + private void RaiseIsAuthenticatedChanged() + => IsAuthenticatedChanged?.Invoke(this, new RoutedEventArgs()); +} \ No newline at end of file diff --git a/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml b/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml new file mode 100644 index 00000000..8b7506c7 --- /dev/null +++ b/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml @@ -0,0 +1,34 @@ + + + + + \ No newline at end of file diff --git a/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml.cs b/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml.cs new file mode 100644 index 00000000..8f21d8f7 --- /dev/null +++ b/src/Atc.Wpf.Controls/ButtonControls/ConnectivityButton.xaml.cs @@ -0,0 +1,137 @@ +// ReSharper disable InvertIf +namespace Atc.Wpf.Controls.ButtonControls; + +public partial class ConnectivityButton +{ + public event RoutedEventHandler? IsConnectedChanged; + + [DependencyProperty(DefaultValue = null)] + private ImageLocation? imageLocation; + + [DependencyProperty(DefaultValue = 16)] + private int imageWidth; + + [DependencyProperty(DefaultValue = 16)] + private int imageHeight; + + [DependencyProperty(DefaultValue = 10d)] + private double imageContentSpacing; + + [DependencyProperty(DefaultValue = 0d)] + private double imageBorderSpacing; + + [DependencyProperty(DefaultValue = false)] + private bool isBusy; + + [DependencyProperty( + DefaultValue = false, + PropertyChangedCallback = nameof(OnIsConnectedChanged))] + private bool isConnected; + + [DependencyProperty] + private object? connectContent; + + [DependencyProperty] + private object? disconnectContent; + + [DependencyProperty] + private ImageSource? connectImageSource; + + [DependencyProperty] + private ImageSource? disconnectImageSource; + + [DependencyProperty(DefaultValue = "")] + private string connectSvgImageSource; + + [DependencyProperty(DefaultValue = "")] + private string disconnectSvgImageSource; + + [DependencyProperty] + private Color? connectSvgImageOverrideColor; + + [DependencyProperty] + private Color? disconnectSvgImageOverrideColor; + + [DependencyProperty] + private ICommand? connectCommand; + + [DependencyProperty] + private ICommand? disconnectCommand; + + public ConnectivityButton() + { + InitializeComponent(); + + SetCurrentValue(ImageLocationProperty, Controls.ImageLocation.Left); + + ThemeManager.Current.ThemeChanged += OnThemeChanged; + } + + protected override void OnInitialized( + EventArgs e) + { + base.OnInitialized(e); + + if (ConnectContent is null or string { Length: 0 }) + { + SetCurrentValue(ConnectContentProperty, Word.Connect); + } + + if (DisconnectContent is null or string { Length: 0 }) + { + SetCurrentValue(DisconnectContentProperty, Word.Disconnect); + } + + if (ConnectImageSource is null && + string.IsNullOrWhiteSpace(ConnectSvgImageSource)) + { + var fgBrush = Application.Current.TryFindResource("AtcApps.Brushes.ThemeForeground"); + + var img = (ImageSource?)FontIconImageSourceValueConverter.Instance + .Convert( + FontMaterialDesignType.Login, + typeof(ImageSource), + fgBrush, + CultureInfo.CurrentUICulture); + + if (img is not null) + { + SetCurrentValue(ConnectImageSourceProperty, img); + } + } + + if (DisconnectImageSource is null && + string.IsNullOrWhiteSpace(DisconnectSvgImageSource)) + { + var accentBrush = Application.Current.TryFindResource("AtcApps.Brushes.Accent"); + + var img = (ImageSource?)FontIconImageSourceValueConverter.Instance + .Convert( + FontMaterialDesignType.Logout, + typeof(ImageSource), + accentBrush, + CultureInfo.CurrentUICulture); + + if (img is not null) + { + SetCurrentValue(DisconnectImageSourceProperty, img); + } + } + } + + private void OnThemeChanged( + object? sender, + ThemeChangedEventArgs e) + { + SetCurrentValue(ConnectContentProperty, Word.Connect); + SetCurrentValue(DisconnectContentProperty, Word.Disconnect); + } + + private static void OnIsConnectedChanged( + DependencyObject d, + DependencyPropertyChangedEventArgs e) + => ((ConnectivityButton)d).RaiseIsConnectedChanged(); + + private void RaiseIsConnectedChanged() + => IsConnectedChanged?.Invoke(this, new RoutedEventArgs()); +} \ No newline at end of file diff --git a/src/Atc.Wpf.Controls/BaseControls/ImageButton.cs b/src/Atc.Wpf.Controls/ButtonControls/ImageButton.cs similarity index 98% rename from src/Atc.Wpf.Controls/BaseControls/ImageButton.cs rename to src/Atc.Wpf.Controls/ButtonControls/ImageButton.cs index e7244e9c..1f162838 100644 --- a/src/Atc.Wpf.Controls/BaseControls/ImageButton.cs +++ b/src/Atc.Wpf.Controls/ButtonControls/ImageButton.cs @@ -1,4 +1,4 @@ -namespace Atc.Wpf.Controls.BaseControls; +namespace Atc.Wpf.Controls.ButtonControls; public partial class ImageButton : Button { diff --git a/src/Atc.Wpf.Controls/BaseControls/ImageButton.xaml b/src/Atc.Wpf.Controls/ButtonControls/ImageButton.xaml similarity index 85% rename from src/Atc.Wpf.Controls/BaseControls/ImageButton.xaml rename to src/Atc.Wpf.Controls/ButtonControls/ImageButton.xaml index 7d3bd52c..a14d16e4 100644 --- a/src/Atc.Wpf.Controls/BaseControls/ImageButton.xaml +++ b/src/Atc.Wpf.Controls/ButtonControls/ImageButton.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:atc="https://github.com/atc-net/atc-wpf/tree/main/schemas" xmlns:atcValueConverters="https://github.com/atc-net/atc-wpf/tree/main/schemas/value-converters" - xmlns:baseControls="clr-namespace:Atc.Wpf.Controls.BaseControls" + xmlns:buttonControls="clr-namespace:Atc.Wpf.Controls.ButtonControls" xmlns:progressing="clr-namespace:Atc.Wpf.Controls.Progressing" xmlns:valueConverters="clr-namespace:Atc.Wpf.Controls.BaseControls.Internal.ValueConverters"> @@ -18,7 +18,7 @@ @@ -150,7 +150,7 @@ @@ -239,25 +239,25 @@ @@ -265,7 +265,7 @@ @@ -291,7 +291,7 @@ @@ -325,7 +325,7 @@ @@ -359,7 +359,7 @@ @@ -393,7 +393,7 @@ @@ -427,7 +427,7 @@ @@ -461,7 +461,7 @@ @@ -495,7 +495,7 @@ @@ -529,7 +529,7 @@ @@ -563,7 +563,7 @@ @@ -597,7 +597,7 @@ @@ -631,7 +631,7 @@ @@ -665,7 +665,7 @@ @@ -699,7 +699,7 @@