From 89f7f2fe68234aa17807f6d28adf53310df4ed63 Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Mon, 15 Jan 2024 06:45:15 +0000 Subject: [PATCH] Added AppBar Added MessageBox - incomplete --- src/CrissCross.WPF.UI.Test/AssemblyInfo.cs | 2 +- .../ViewModels/DashboardViewModel.cs | 8 +- .../Views/MainWindow.xaml | 9 + src/CrissCross.WPF.UI/AssemblyInfo.cs | 2 +- src/CrissCross.WPF.UI/Controls/AppBar.xaml | 79 ++++ src/CrissCross.WPF.UI/Controls/AppBar.xaml.cs | 217 +++++++++ .../Controls/MessageBox.xaml | 65 +++ .../Controls/MessageBox.xaml.cs | 417 ++++++++++++++++++ .../CrissCross.WPF.UI.csproj | 10 + .../Themes/CrissCross.Wpf.UI.xaml | 6 +- src/CrissCross.WPF.UI/Themes/Generic.xaml | 6 - .../Themes/ModernWindow.xaml | 16 +- src/CrissCross.WPF/ViewModelRoutedViewHost.cs | 37 +- 13 files changed, 850 insertions(+), 24 deletions(-) create mode 100644 src/CrissCross.WPF.UI/Controls/AppBar.xaml create mode 100644 src/CrissCross.WPF.UI/Controls/AppBar.xaml.cs create mode 100644 src/CrissCross.WPF.UI/Controls/MessageBox.xaml create mode 100644 src/CrissCross.WPF.UI/Controls/MessageBox.xaml.cs delete mode 100644 src/CrissCross.WPF.UI/Themes/Generic.xaml diff --git a/src/CrissCross.WPF.UI.Test/AssemblyInfo.cs b/src/CrissCross.WPF.UI.Test/AssemblyInfo.cs index 7386153..46be665 100644 --- a/src/CrissCross.WPF.UI.Test/AssemblyInfo.cs +++ b/src/CrissCross.WPF.UI.Test/AssemblyInfo.cs @@ -1,4 +1,4 @@ // Copyright (c) Chris Pulman. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] +[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)] diff --git a/src/CrissCross.WPF.UI.Test/ViewModels/DashboardViewModel.cs b/src/CrissCross.WPF.UI.Test/ViewModels/DashboardViewModel.cs index 6438ca8..500a36a 100644 --- a/src/CrissCross.WPF.UI.Test/ViewModels/DashboardViewModel.cs +++ b/src/CrissCross.WPF.UI.Test/ViewModels/DashboardViewModel.cs @@ -10,7 +10,7 @@ namespace CrissCross.WPF.UI.Test.ViewModels; /// DashboardViewModel. /// /// -public class DashboardViewModel : RxObject +public class DashboardViewModel : RxObject, IControlAppBar { private int _counter; @@ -39,5 +39,9 @@ public int Counter /// public ReactiveCommand CounterIncrementCommand { get; } - private void OnCounterIncrement() => Counter++; + private void OnCounterIncrement() + { + Counter++; + this.ShowAppBar(); + } } diff --git a/src/CrissCross.WPF.UI.Test/Views/MainWindow.xaml b/src/CrissCross.WPF.UI.Test/Views/MainWindow.xaml index 3a29f95..515a9e6 100644 --- a/src/CrissCross.WPF.UI.Test/Views/MainWindow.xaml +++ b/src/CrissCross.WPF.UI.Test/Views/MainWindow.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:CrissCross.WPF.UI.Test.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:rxNav="clr-namespace:CrissCross.WPF.UI;assembly=CrissCross.WPF.UI" xmlns:tray="http://schemas.lepo.co/wpfui/2022/xaml/tray" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="{Binding ViewModel.ApplicationTitle, Mode=OneWay}" @@ -74,5 +75,13 @@ + + + + + diff --git a/src/CrissCross.WPF.UI/AssemblyInfo.cs b/src/CrissCross.WPF.UI/AssemblyInfo.cs index febdf75..a51c331 100644 --- a/src/CrissCross.WPF.UI/AssemblyInfo.cs +++ b/src/CrissCross.WPF.UI/AssemblyInfo.cs @@ -6,4 +6,4 @@ [assembly: XmlnsDefinition("https://github.com/ChrisPulman/CrissCross", "CrissCross.WPF.UI")] [assembly: XmlnsPrefix("https://github.com/ChrisPulman/CrissCross", "rxNav")] -[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] +[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)] diff --git a/src/CrissCross.WPF.UI/Controls/AppBar.xaml b/src/CrissCross.WPF.UI/Controls/AppBar.xaml new file mode 100644 index 0000000..ea5a83c --- /dev/null +++ b/src/CrissCross.WPF.UI/Controls/AppBar.xaml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CrissCross.WPF.UI/Controls/AppBar.xaml.cs b/src/CrissCross.WPF.UI/Controls/AppBar.xaml.cs new file mode 100644 index 0000000..2eac359 --- /dev/null +++ b/src/CrissCross.WPF.UI/Controls/AppBar.xaml.cs @@ -0,0 +1,217 @@ +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Windows; +using System.Windows.Input; +using System.Windows.Media.Animation; +using ReactiveMarbles.ObservableEvents; + +namespace CrissCross.WPF.UI +{ + /// + /// Interaction logic for AppBar.xaml. + /// + public partial class AppBar : IHaveAppBar + { + /// + /// The application bar enabled property. + /// + public static readonly DependencyProperty AppBarEnabledProperty = DependencyProperty.Register(nameof(AppBarEnabled), typeof(bool), typeof(ModernWindow), new PropertyMetadata(true)); + + /// + /// Holds AppBar open until explicitly closed. + /// + public static readonly DependencyProperty AppBarIsStickyProperty = DependencyProperty.Register(nameof(AppBarIsSticky), typeof(bool), typeof(ModernWindow), new PropertyMetadata(false)); + + /// + /// Recommended Height 88. + /// + public static readonly DependencyProperty AppBarLeftProperty = DependencyProperty.Register(nameof(AppBarLeft), typeof(ObservableCollection), typeof(ModernWindow)); + + /// + /// Recommended Height 88. + /// + public static readonly DependencyProperty AppBarRightProperty = DependencyProperty.Register(nameof(AppBarRight), typeof(ObservableCollection), typeof(ModernWindow)); + + private readonly Storyboard? _hide; + private readonly Storyboard? _show; + private bool _appBarVisible; + private bool _mouseIsOverAppBar; + + /// + /// Initializes a new instance of the class. + /// + public AppBar() + { + InitializeComponent(); + AppBarLeft = []; + AppBarRight = []; + AppBarLeftControl.ItemsSource = AppBarLeft; + AppBarRightControl.ItemsSource = AppBarRight; + _hide = BottomAppBar.Resources["Hide"] as Storyboard; + _show = BottomAppBar.Resources["Show"] as Storyboard; + BottomAppBar.MouseEnter += AppBar_MouseEnter; + BottomAppBar.MouseLeave += AppBar_MouseLeave; + + HideAppBar(); + this.Events().Loaded.Subscribe(_ => + { + // Find the parent window + var parentWindow = Window.GetWindow(this); + if (parentWindow != null) + { + parentWindow.PreviewMouseDown += ModernWindow_PreviewMouseDown; + } + + this.AppBarIsStickyListener(() => AppBarIsSticky, isSticky => AppBarIsSticky = isSticky); + this.AppBarLeftListener(() => AppBarLeft); + this.AppBarRightListener(() => AppBarRight); + this.ShowAppBarListener(ShowAppBar); + this.HideAppBarListener(HideAppBar); + }); + } + + /// + /// Gets or sets a value indicating whether [application bar enabled]. + /// + /// true if [application bar enabled]; otherwise, false . + [Description("Gets or Sets the Visibility of the Nav Bar")] + [Category("CrissCross")] + public bool AppBarEnabled + { + get => (bool)GetValue(AppBarEnabledProperty); + + set + { + SetValue(AppBarEnabledProperty, value); + if (!value) + { + HideAppBar(); + } + } + } + + /// + /// Gets a value indicating whether [application bar is sticky]. + /// + /// true if [application bar is sticky]; otherwise, false . + [Description("Gets the AppBar Sticky state.")] + [Category("CrissCross")] + public bool AppBarIsSticky + { + get => (bool)GetValue(AppBarIsStickyProperty); + + private set => SetValue(AppBarIsStickyProperty, value); + } + + /// + /// Gets or sets the AppBarLeft content. + /// + [Description("Gets or sets the AppBarLeft content.")] + [Category("CrissCross")] + public ObservableCollection AppBarLeft + { + get => (ObservableCollection)GetValue(AppBarLeftProperty); + set => SetValue(AppBarLeftProperty, value); + } + + /// + /// Gets or sets the AppBarRight content. + /// + [Description("Gets or sets the AppBarRight content.")] + [Category("CrissCross")] + public ObservableCollection AppBarRight + { + get => (ObservableCollection)GetValue(AppBarRightProperty); + set => SetValue(AppBarRightProperty, value); + } + + /// + /// Gets the template child. + /// + /// The element type. + /// The name. + /// The Instance if exists. + /// name. + protected T GetTemplateChild(string name) + where T : DependencyObject + { + if (GetTemplateChild(name) is not T dependencyObject) + { + throw new ArgumentNullException(name); + } + + return dependencyObject; + } + + /// + /// Shows the application bar. + /// + /// if set to true [is sticky]. + private void ShowAppBar(bool isSticky = false) + { + if (!AppBarEnabled) + { + HideAppBar(); + return; + } + + AppBarIsSticky = isSticky; + if (_show != null && !_appBarVisible) + { + _show.Begin(); + _appBarVisible = true; + } + } + + /// + /// Hides the application bar. + /// + private void HideAppBar() + { + if (_hide != null && _appBarVisible) + { + _hide.Begin(); + _appBarVisible = false; + } + } + + /// + /// Handles the MouseEnter event of the _AppBar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void AppBar_MouseEnter(object sender, MouseEventArgs e) => _mouseIsOverAppBar = true; + + /// + /// Handles the MouseLeave event of the _AppBar control. + /// + /// The source of the event. + /// The instance containing the event data. + private void AppBar_MouseLeave(object sender, MouseEventArgs e) => _mouseIsOverAppBar = false; + + /// + /// Handles the PreviewMouseDown event of the ModernWindow control. + /// + /// The source of the event. + /// + /// The instance containing the event data. + /// + private void ModernWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e) + { + if (!_mouseIsOverAppBar) + { + if (!_appBarVisible && e.ButtonState == MouseButtonState.Pressed && e.ChangedButton == MouseButton.Right) + { + ShowAppBar(); + } + else if (_appBarVisible && e.ChangedButton != MouseButton.Right && !AppBarIsSticky) + { + HideAppBar(); + } + } + } + } +} diff --git a/src/CrissCross.WPF.UI/Controls/MessageBox.xaml b/src/CrissCross.WPF.UI/Controls/MessageBox.xaml new file mode 100644 index 0000000..83b71bc --- /dev/null +++ b/src/CrissCross.WPF.UI/Controls/MessageBox.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CrissCross.WPF.UI/Controls/MessageBox.xaml.cs b/src/CrissCross.WPF.UI/Controls/MessageBox.xaml.cs new file mode 100644 index 0000000..5ad72c7 --- /dev/null +++ b/src/CrissCross.WPF.UI/Controls/MessageBox.xaml.cs @@ -0,0 +1,417 @@ +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reactive; +using System.Windows; +using System.Windows.Input; +using CP.BBCode.WPF; +using ReactiveUI; +using Wpf.Ui.Controls; +using MessageBoxButton = System.Windows.MessageBoxButton; +using MessageBoxResult = System.Windows.MessageBoxResult; + +namespace CrissCross.WPF.UI +{ + /// + /// Interaction logic for MessageBox.xaml. + /// + public partial class MessageBox : IListenForMessages, ICanShowMessages + { + /// + /// Identifies the Buttons dependency property. + /// + public static readonly DependencyProperty ButtonsProperty = DependencyProperty.Register(nameof(Buttons), typeof(IEnumerable