From 09bab4932100e2fd4ca6e31f400378aa64ce07cd Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 13:03:54 +0600 Subject: [PATCH 01/90] implemented navigation back --- src/Wpf.Ui/Controls/Interfaces/INavigation.cs | 6 ++ .../Controls/Navigation/NavigationBase.cs | 100 ++++++++---------- .../Services/Internal/NavigationService.cs | 41 ++++++- 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/Wpf.Ui/Controls/Interfaces/INavigation.cs b/src/Wpf.Ui/Controls/Interfaces/INavigation.cs index 8be422a96..663d98d2c 100644 --- a/src/Wpf.Ui/Controls/Interfaces/INavigation.cs +++ b/src/Wpf.Ui/Controls/Interfaces/INavigation.cs @@ -107,6 +107,12 @@ public interface INavigation /// void ClearCache(); + /// + /// Navigates to the previous page using the . + /// + /// + bool NavigateBack(); + /// /// Navigates to the page using the . /// diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs b/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs index fb7488191..923225bb8 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs @@ -99,6 +99,13 @@ public abstract class NavigationBase : System.Windows.Controls.Control, INavigat typeof(bool), typeof(NavigationBase), new PropertyMetadata(false)); + /// + /// Property for . + /// + public static readonly DependencyProperty BackButtonCommandProperty = + DependencyProperty.Register(nameof(BackButtonCommand), + typeof(Common.IRelayCommand), typeof(NavigationFluent), new PropertyMetadata(null)); + /// /// Attached property for 's to get its parent. /// @@ -163,6 +170,11 @@ public bool Precache set => SetValue(PrecacheProperty, value); } + /// + /// Command triggered after clicking the back button. + /// + public Common.IRelayCommand BackButtonCommand => (Common.IRelayCommand)GetValue(BackButtonCommandProperty); + internal INavigation NavigationParent { get => (INavigation)GetValue(NavigationParentProperty); @@ -227,11 +239,6 @@ public IPageService? PageService /// public INavigationItem? Current { get; internal set; } - /// - /// Navigation history containing pages tags. - /// - public readonly List History; - /// /// Static constructor overriding default properties. /// @@ -252,7 +259,6 @@ static NavigationBase() protected NavigationBase() { Current = (INavigationItem)null; - History = new List(); // Prepare individual collections for this navigation Items ??= new ObservableCollection(); @@ -262,6 +268,8 @@ protected NavigationBase() _navigationService.TransitionDuration = TransitionDuration; _navigationService.TransitionType = TransitionType; + SetValue(BackButtonCommandProperty, new Common.RelayCommand(o => NavigateBack(), () => _navigationService.ReadyToNavigateBack)); + if (Frame != null) _navigationService.SetFrame(Frame); @@ -272,6 +280,18 @@ protected NavigationBase() Loaded += OnLoaded; } + public bool NavigateBack() + { + if (_navigationService is null) return false; + + if (!_navigationService.NavigateBack()) + return false; + + NavigateInternal(0, true); + + return true; + } + /// public bool Navigate(Type pageType) { @@ -284,16 +304,7 @@ public bool Navigate(Type pageType, object? dataContext) if (!_navigationService.Navigate(pageType, dataContext)) return false; - SelectedPageIndex = _navigationService.GetCurrentId(); - - UpdateItems(); - - OnNavigated(); - - if (_navigationService.GetCurrentId() > _navigationService.GetPreviousId()) - OnNavigatedForward(); - else - OnNavigatedBackward(); + NavigateInternal(0, true); return true; } @@ -310,16 +321,7 @@ public bool Navigate(string pageTag, object? dataContext) if (!_navigationService.Navigate(pageTag, dataContext)) return false; - SelectedPageIndex = _navigationService.GetCurrentId(); - - UpdateItems(); - - OnNavigated(); - - if (_navigationService.GetCurrentId() > _navigationService.GetPreviousId()) - OnNavigatedForward(); - else - OnNavigatedBackward(); + NavigateInternal(0, true); return true; } @@ -338,16 +340,7 @@ public bool Navigate(int pageId, object? dataContext) if (!_navigationService.Navigate(pageId, dataContext)) return false; - SelectedPageIndex = _navigationService?.GetCurrentId() ?? -1; - - UpdateItems(); - - OnNavigated(); - - if (SelectedPageIndex > (_navigationService?.GetPreviousId() ?? -1)) - OnNavigatedForward(); - else - OnNavigatedBackward(); + NavigateInternal(-1, true); return true; } @@ -365,16 +358,7 @@ public bool NavigateExternal(object frameworkElement, object? dataContext) if (!_navigationService.NavigateExternal(frameworkElement, dataContext)) return false; - SelectedPageIndex = _navigationService?.GetCurrentId() ?? -1; - - UpdateItems(); - - OnNavigated(); - - if (SelectedPageIndex > (_navigationService?.GetPreviousId() ?? -1)) - OnNavigatedForward(); - else - OnNavigatedBackward(); + NavigateInternal(-1, true); return true; } @@ -392,14 +376,7 @@ public bool NavigateExternal(Uri absolutePageUri, object? dataContext) if (!_navigationService.NavigateExternal(absolutePageUri, dataContext)) return false; - SelectedPageIndex = _navigationService?.GetCurrentId() ?? -1; - - OnNavigated(); - - if (SelectedPageIndex > (_navigationService?.GetPreviousId() ?? -1)) - OnNavigatedForward(); - else - OnNavigatedBackward(); + NavigateInternal(-1, false); return true; } @@ -740,4 +717,19 @@ private void UpdateServiceItems() if (_navigationService != null) _navigationService.UpdateItems(navigationItems, navigationFooter); } + + private void NavigateInternal(int arg, bool updateItems) + { + SelectedPageIndex = _navigationService?.GetCurrentId() ?? + arg; + + if (updateItems) + UpdateItems(); + + OnNavigated(); + + if (SelectedPageIndex > (_navigationService?.GetPreviousId() ?? + arg)) + OnNavigatedForward(); + else + OnNavigatedBackward(); + } } diff --git a/src/Wpf.Ui/Services/Internal/NavigationService.cs b/src/Wpf.Ui/Services/Internal/NavigationService.cs index 151a14e1a..b4b30ed82 100644 --- a/src/Wpf.Ui/Services/Internal/NavigationService.cs +++ b/src/Wpf.Ui/Services/Internal/NavigationService.cs @@ -71,6 +71,13 @@ internal sealed class NavigationService : IDisposable /// private NavigationServiceItem[] _navigationServiceItems; + /// + /// + /// + private readonly List _history; + + private bool _isBackNavigated; + #endregion Private properties #region Public properties @@ -90,6 +97,11 @@ internal sealed class NavigationService : IDisposable /// public TransitionType TransitionType { get; set; } + /// + /// Indicates the possibility of navigation back + /// + public bool ReadyToNavigateBack => _history.Count > 1; + #endregion Public properties #region Constructors @@ -101,6 +113,7 @@ public NavigationService() { _eventIdentifier = new EventIdentifier(); _navigationServiceItems = new NavigationServiceItem[] { }; + _history = new List(); } /// @@ -115,6 +128,14 @@ public NavigationService() #region Public methods + public bool NavigateBack() + { + if (_history.Count <= 1) return false; + + _isBackNavigated = true; + return NavigateInternal(_history[_history.Count - 2], null); + } + /// /// Navigates the based on provided item Id. /// @@ -518,7 +539,7 @@ private bool NavigateInternalByItemWithCache(int serviceItemId, object dataConte System.Diagnostics.Debug.WriteLine( $"DEBUG | {_navigationServiceItems[serviceItemId].Tag} navigated internally, with cache by it's instance."); #endif - + AddToHistory(serviceItemId); return true; } @@ -540,7 +561,7 @@ private bool NavigateInternalByItemWithCache(int serviceItemId, object dataConte System.Diagnostics.Debug.WriteLine( $"DEBUG | {_navigationServiceItems[serviceItemId].Tag} navigated internally, with cache by it's type."); #endif - + AddToHistory(serviceItemId); return true; } @@ -561,6 +582,7 @@ private bool NavigateInternalByItemWithCache(int serviceItemId, object dataConte $"DEBUG | {_navigationServiceItems[serviceItemId].Tag} navigated internally, with cache by it's source."); #endif + AddToHistory(serviceItemId); return true; } @@ -597,6 +619,7 @@ private bool NavigateInternalByItemWithoutCache(int serviceItemId, object dataCo System.Diagnostics.Debug.WriteLine( $"DEBUG | {_navigationServiceItems[serviceItemId].Tag} navigated internally, without cache by it's type."); #endif + AddToHistory(serviceItemId); return true; } @@ -616,6 +639,7 @@ private bool NavigateInternalByItemWithoutCache(int serviceItemId, object dataCo $"DEBUG | {_navigationServiceItems[serviceItemId].Tag} navigated internally, without cache by it's source."); #endif + AddToHistory(serviceItemId); return true; } @@ -637,10 +661,23 @@ private bool NavigateInternalByService(int serviceItemId) throw new InvalidOperationException($"The {_navigationServiceItems[serviceItemId].Type} has not been registered in the {typeof(IPageService)} service."); _frame.Navigate(servicePageInstance); + AddToHistory(serviceItemId); return true; } + private void AddToHistory(int serviceItemId) + { + if (_isBackNavigated) + { + _isBackNavigated = false; + _history.RemoveAt(_history.LastIndexOf(_history[_history.Count - 2])); + _history.RemoveAt(_history.LastIndexOf(_history[_history.Count - 1])); + } + + _history.Add(serviceItemId); + } + #endregion Internal navigation #region Instance management From c22e931f659d2bf14f60e6a496f1b943c9316141 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 13:10:11 +0600 Subject: [PATCH 02/90] added back button style --- src/Wpf.Ui/Styles/Controls/Button.xaml | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/Wpf.Ui/Styles/Controls/Button.xaml b/src/Wpf.Ui/Styles/Controls/Button.xaml index 1620cb9b1..c9bfc6a0e 100644 --- a/src/Wpf.Ui/Styles/Controls/Button.xaml +++ b/src/Wpf.Ui/Styles/Controls/Button.xaml @@ -440,4 +440,93 @@ + From 9b93b3bd1cfa2509fe4b6ed0029dccba3e5b309d Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 13:21:25 +0600 Subject: [PATCH 03/90] added back button to the settings window --- src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml | 10 ++++++++++ src/Wpf.Ui/Styles/Controls/Button.xaml | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml b/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml index 85a0d6c2b..c2e729779 100644 --- a/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml +++ b/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml @@ -175,5 +175,15 @@ + + diff --git a/src/Wpf.Ui/Styles/Controls/Button.xaml b/src/Wpf.Ui/Styles/Controls/Button.xaml index c9bfc6a0e..61a30cf49 100644 --- a/src/Wpf.Ui/Styles/Controls/Button.xaml +++ b/src/Wpf.Ui/Styles/Controls/Button.xaml @@ -454,7 +454,6 @@ - From 52704c1b7394a0a05dbd9fa8dbe81044d650859f Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:44:22 +0600 Subject: [PATCH 04/90] added NavigationBackButton control --- .../Views/Windows/SettingsWindow.xaml | 10 +- src/Wpf.Ui/Controls/Interfaces/INavigation.cs | 5 + .../Navigation/NavigationBackButton.cs | 33 +++++++ .../Controls/Navigation/NavigationBase.cs | 17 +--- .../Services/Internal/NavigationService.cs | 2 +- src/Wpf.Ui/Styles/Controls/Button.xaml | 88 ----------------- .../Styles/Controls/NavigationBackButton.xaml | 96 +++++++++++++++++++ src/Wpf.Ui/Styles/Wpf.Ui.xaml | 1 + 8 files changed, 142 insertions(+), 110 deletions(-) create mode 100644 src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs create mode 100644 src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml diff --git a/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml b/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml index c2e729779..ebdc038c8 100644 --- a/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml +++ b/src/Wpf.Ui.Demo/Views/Windows/SettingsWindow.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Wpf.Ui.Demo.Views.Windows" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:navigation="clr-namespace:Wpf.Ui.Controls.Navigation;assembly=Wpf.Ui" xmlns:pages="clr-namespace:Wpf.Ui.Demo.Views.Pages" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="WPF UI - Editor" @@ -176,14 +177,9 @@ - + Navigation="{Binding ElementName=RootNavigation, Mode=OneTime}" /> diff --git a/src/Wpf.Ui/Controls/Interfaces/INavigation.cs b/src/Wpf.Ui/Controls/Interfaces/INavigation.cs index 663d98d2c..a75d4cb27 100644 --- a/src/Wpf.Ui/Controls/Interfaces/INavigation.cs +++ b/src/Wpf.Ui/Controls/Interfaces/INavigation.cs @@ -39,6 +39,11 @@ public interface INavigation /// bool Precache { get; set; } + /// + /// Indicates the possibility of navigation back + /// + bool CanGoBack { get; } + /// /// Currently used item like . /// diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs b/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs new file mode 100644 index 000000000..44fc047be --- /dev/null +++ b/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs @@ -0,0 +1,33 @@ +#nullable enable +using System.ComponentModel; +using System.Windows; +using Wpf.Ui.Controls.Interfaces; + +namespace Wpf.Ui.Controls.Navigation; + +/// +/// Inherited from the , used to navigate backwards/>. +/// +public class NavigationBackButton : Button +{ + /// + /// Property for . + /// + public static readonly DependencyProperty NavigationProperty = DependencyProperty.Register(nameof(Navigation), + typeof(INavigation), typeof(NavigationBackButton), new PropertyMetadata(null)); + + /// + /// + /// + [Bindable(true), Category("Behavior")] + public INavigation? Navigation + { + get => (INavigation)GetValue(NavigationProperty); + set => SetValue(NavigationProperty, value); + } + + public NavigationBackButton() + { + SetValue(CommandProperty, new Common.RelayCommand(o => Navigation?.NavigateBack(), () => Navigation is not null && Navigation.CanGoBack)); + } +} diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs b/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs index 923225bb8..a2983b9ae 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationBase.cs @@ -99,13 +99,6 @@ public abstract class NavigationBase : System.Windows.Controls.Control, INavigat typeof(bool), typeof(NavigationBase), new PropertyMetadata(false)); - /// - /// Property for . - /// - public static readonly DependencyProperty BackButtonCommandProperty = - DependencyProperty.Register(nameof(BackButtonCommand), - typeof(Common.IRelayCommand), typeof(NavigationFluent), new PropertyMetadata(null)); - /// /// Attached property for 's to get its parent. /// @@ -170,11 +163,6 @@ public bool Precache set => SetValue(PrecacheProperty, value); } - /// - /// Command triggered after clicking the back button. - /// - public Common.IRelayCommand BackButtonCommand => (Common.IRelayCommand)GetValue(BackButtonCommandProperty); - internal INavigation NavigationParent { get => (INavigation)GetValue(NavigationParentProperty); @@ -236,6 +224,9 @@ public IPageService? PageService /// public int PreviousPageIndex => _navigationService?.GetPreviousId() ?? 0; + /// + public bool CanGoBack => _navigationService is not null && _navigationService.CanGoBack; + /// public INavigationItem? Current { get; internal set; } @@ -268,8 +259,6 @@ protected NavigationBase() _navigationService.TransitionDuration = TransitionDuration; _navigationService.TransitionType = TransitionType; - SetValue(BackButtonCommandProperty, new Common.RelayCommand(o => NavigateBack(), () => _navigationService.ReadyToNavigateBack)); - if (Frame != null) _navigationService.SetFrame(Frame); diff --git a/src/Wpf.Ui/Services/Internal/NavigationService.cs b/src/Wpf.Ui/Services/Internal/NavigationService.cs index b4b30ed82..63e494c02 100644 --- a/src/Wpf.Ui/Services/Internal/NavigationService.cs +++ b/src/Wpf.Ui/Services/Internal/NavigationService.cs @@ -100,7 +100,7 @@ internal sealed class NavigationService : IDisposable /// /// Indicates the possibility of navigation back /// - public bool ReadyToNavigateBack => _history.Count > 1; + public bool CanGoBack => _history.Count > 1; #endregion Public properties diff --git a/src/Wpf.Ui/Styles/Controls/Button.xaml b/src/Wpf.Ui/Styles/Controls/Button.xaml index 61a30cf49..1620cb9b1 100644 --- a/src/Wpf.Ui/Styles/Controls/Button.xaml +++ b/src/Wpf.Ui/Styles/Controls/Button.xaml @@ -440,92 +440,4 @@ - diff --git a/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml new file mode 100644 index 000000000..013ebc289 --- /dev/null +++ b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml @@ -0,0 +1,96 @@ + + + + + \ No newline at end of file diff --git a/src/Wpf.Ui/Styles/Wpf.Ui.xaml b/src/Wpf.Ui/Styles/Wpf.Ui.xaml index e96ccaa50..174424507 100644 --- a/src/Wpf.Ui/Styles/Wpf.Ui.xaml +++ b/src/Wpf.Ui/Styles/Wpf.Ui.xaml @@ -30,6 +30,7 @@ + From 2ed47eec96f4556003bb1376f8315c21041c8326 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 16:05:08 +0600 Subject: [PATCH 05/90] the NavigationBackButton now inherits System.Windows.Controls.Button --- src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs | 4 ++-- src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs b/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs index 44fc047be..9ce4f646c 100644 --- a/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs +++ b/src/Wpf.Ui/Controls/Navigation/NavigationBackButton.cs @@ -6,9 +6,9 @@ namespace Wpf.Ui.Controls.Navigation; /// -/// Inherited from the , used to navigate backwards/>. +/// Inherited from the , used to navigate backwards/>. /// -public class NavigationBackButton : Button +public class NavigationBackButton : System.Windows.Controls.Button { /// /// Property for . diff --git a/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml index 013ebc289..45f2f05fb 100644 --- a/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml +++ b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml @@ -10,17 +10,11 @@ - - - - - - From 1cd79e4bd78e41828ea4c89ed06503cb60229f41 Mon Sep 17 00:00:00 2001 From: Ivan Dmitriev <42055372+IvanDmitriev1@users.noreply.github.com> Date: Tue, 19 Jul 2022 16:07:51 +0600 Subject: [PATCH 06/90] Update AssemblyInfo.cs --- src/Wpf.Ui/Properties/AssemblyInfo.cs | 1 + src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Wpf.Ui/Properties/AssemblyInfo.cs b/src/Wpf.Ui/Properties/AssemblyInfo.cs index 4c17367f4..27037b5a8 100644 --- a/src/Wpf.Ui/Properties/AssemblyInfo.cs +++ b/src/Wpf.Ui/Properties/AssemblyInfo.cs @@ -17,3 +17,4 @@ [assembly: XmlnsDefinition("http://schemas.lepo.co/wpfui/2022/xaml", "Wpf.Ui.Markup")] [assembly: XmlnsDefinition("http://schemas.lepo.co/wpfui/2022/xaml", "Wpf.Ui.Converters")] [assembly: XmlnsDefinition("http://schemas.lepo.co/wpfui/2022/xaml", "Wpf.Ui.ValidationRules")] +[assembly: XmlnsDefinition("http://schemas.lepo.co/wpfui/2022/xaml", "Wpf.Ui.Controls.Navigation")] diff --git a/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml index 45f2f05fb..bcf9586bf 100644 --- a/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml +++ b/src/Wpf.Ui/Styles/Controls/NavigationBackButton.xaml @@ -2,9 +2,9 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Wpf.Ui.Controls" - xmlns:navigation="clr-namespace:Wpf.Ui.Controls.Navigation"> + xmlns:ui="clr-namespace:Wpf.Ui.Controls.Navigation"> - + + + + - - diff --git a/src/Wpf.Ui/Styles/Controls/NavigationHeader.xaml b/src/Wpf.Ui/Styles/Controls/NavigationHeader.xaml index 318bede10..099b19c15 100644 --- a/src/Wpf.Ui/Styles/Controls/NavigationHeader.xaml +++ b/src/Wpf.Ui/Styles/Controls/NavigationHeader.xaml @@ -8,9 +8,10 @@ + xmlns:controls="clr-namespace:Wpf.Ui.Controls" + xmlns:navigation="clr-namespace:Wpf.Ui.Controls.Navigation"> - diff --git a/src/Wpf.Ui/Wpf.Ui.csproj b/src/Wpf.Ui/Wpf.Ui.csproj index 4f02f4ec1..c723d1d40 100644 --- a/src/Wpf.Ui/Wpf.Ui.csproj +++ b/src/Wpf.Ui/Wpf.Ui.csproj @@ -121,9 +121,9 @@ - + - + From 20b114ca597d3c7446272bfbce189fe193fa9bfd Mon Sep 17 00:00:00 2001 From: pomianowski Date: Sat, 30 Jul 2022 17:28:03 +0200 Subject: [PATCH 26/90] Update docs [#239][#311][#307][skip ci] --- docs/CONTROLS.md | 7 ++-- docs/ICONS.md | 18 +++++++--- docs/MENU.md | 24 ++++++------- docs/NAVIGATION.md | 85 +++++++++++++++++++++------------------------- docs/PAGES.md | 8 +++++ docs/SERVICES.md | 4 +-- docs/THEMES.md | 14 ++++---- docs/TUTORIAL.md | 58 +++++++++++++++++++------------ 8 files changed, 122 insertions(+), 96 deletions(-) diff --git a/docs/CONTROLS.md b/docs/CONTROLS.md index 08917b929..bc8191fc9 100644 --- a/docs/CONTROLS.md +++ b/docs/CONTROLS.md @@ -2,12 +2,11 @@ **WPF UI** has two kinds of controls. Default WPF ones, which styles have been overridden, and custom proprietary controls like `ProgressRing`. ### Access to custom controls -In order for your `Window`, `Page`, or `UserControl` to use custom **WPF UI** controls, you need to add `wpfui` namespace. +In order for your `Window`, `Page`, or `UserControl` to use custom **WPF UI** controls, you need to add `ui` namespace. ```xml + ... + xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"> ``` diff --git a/docs/ICONS.md b/docs/ICONS.md index d61157703..72307fcf9 100644 --- a/docs/ICONS.md +++ b/docs/ICONS.md @@ -4,13 +4,14 @@ ## Getting started Icons are displayed by using the font that comes with the library. All glyphs are mapped to the [SymbolRegular](https://github.com/lepoco/wpfui/blob/main/src/Wpf.Ui/Common/SymbolRegular.cs) and [SymbolFilled](https://github.com/lepoco/wpfui/blob/main/src/Wpf.Ui/Common/SymbolFilled.cs) enums. -Icon controls and fonts will be automatically added to your application if you add `Resources` in the **App.xaml** file: +Icon controls and fonts will be automatically added to your application if you add `ControlsDictionary` in the **App.xaml** file: ```xml - + + ``` @@ -95,6 +96,15 @@ According to the EULA of Segoe Fluent Icons we cannot ship a copy of it with thi [https://docs.microsoft.com/en-us/windows/apps/design/downloads/#fonts](https://docs.microsoft.com/en-us/windows/apps/design/downloads/#fonts) In the `App.xaml` dictionaries, you can add an alternate path to the font -```XML -pack://application:,,,/;component/Fonts/#Segoe Fluent Icons +```xml + + + + + + pack://application:,,,/;component/Fonts/#Segoe Fluent Icons + + ``` \ No newline at end of file diff --git a/docs/MENU.md b/docs/MENU.md index 793c71fb1..73702c57b 100644 --- a/docs/MENU.md +++ b/docs/MENU.md @@ -6,13 +6,13 @@ An interesting menu, you can create, for example, this way. ```xml - - @@ -21,33 +21,33 @@ An interesting menu, you can create, for example, this way. - + - - + + - + - - - - - + + + + - + diff --git a/docs/NAVIGATION.md b/docs/NAVIGATION.md index 5ca92618c..d688cf183 100644 --- a/docs/NAVIGATION.md +++ b/docs/NAVIGATION.md @@ -5,110 +5,103 @@ The `Navigation` control stores information about the currently displayed pages and provides methods related to navigation. You can create it in your XAML files or in code. -After the navigation is rendered, it will automatically navigate to the first page added to `Items`. +After the navigation is rendered, it will automatically navigate to the first page added to `Items` _(if the SelectedPageIndex is set above -1)_. You can navigate manually using the Navigate method. ```cpp RootNavigation.Navigate("dashboard"); +RootNavigation.Navigate(typeof(MyDashboardClass)); ``` The Navigate method uses `PageTag` parameter of the `NavigationItem` to detect what page you want to navigate to. If you don't define it, it will be added automatically. -If `Content` of the `NavigationItem` is **HomePage**, the automatically generated tag will be **homepage**. +If `Content` of the `NavigationItem` is **HomePage** string, the automatically generated tag will be **homepage**. -Additionally, you can choose whether the instance you are navigating to should be recreated and pass the view context. +You can also navigate using an index like an array. +`Items` and `Footer` are treated as one array. So if you have two `NavigationItem` in `Items` and another two in the `Footer` then `RootNavigation.Navigate(2)`, will navigate to the third index (counting from zero), which is first item in the `Footer`. ```cpp -RootNavigation.Navigate( - "dashboard", // Tag of the Navigationitem - false, // Do you want to reset the page instance? - _myData // Some object, preferably an ObservableCollection that contains your page data -); -``` - -You can also navigate using an index like an array. -```cpp -// 1, which is index 1, which is the second NavigationItem added to Items -RootNavigation.Navigate(1); +// 2, which is index 2 (third element), which is the third NavigationItem added to Items and Footer +RootNavigation.Navigate(2); ``` ## NavigationStore It is similar to the navigation from the Windows Store. ```xml - - - + + - - - + + + PageType="{x:Type pages:Settings}" /> - - - + + ``` ## NavigationCompact It is similar to the navigation from the Windows 11 Task Manager. ```xml - - - + - - - + + + PageType="{x:Type pages:Settings}" /> - - - + + ``` ## NavigationFluent It is similar to the navigation from the Windows 11 Settings app. ```xml - - - + - - - + + - - - + + ``` \ No newline at end of file diff --git a/docs/PAGES.md b/docs/PAGES.md index 8812fa83a..d97c61678 100644 --- a/docs/PAGES.md +++ b/docs/PAGES.md @@ -30,4 +30,12 @@ You can also use an other style, `UiPageScrollable`, which automatically adds a Style="{StaticResource UiPageScrollable}" mc:Ignorable="d"> +``` + +## Custom control +```xml + ``` \ No newline at end of file diff --git a/docs/SERVICES.md b/docs/SERVICES.md index 76d36387d..509f5a9db 100644 --- a/docs/SERVICES.md +++ b/docs/SERVICES.md @@ -9,8 +9,8 @@ Model–view–viewmodel (MVVM) is a software architectural pattern that facilit **DI** In software engineering, dependency injection is a design pattern in which an object receives other objects that it depends on. A form of inversion of control, dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs.[^2] -**Sources in WPF UI** -The classes and interfaces created for MVVM and DI are in the namespace: +**Sources in WPF UI** +The classes and interfaces created for MVVM and DI are located in the namespace: ```cpp namespace Wpf.Ui.Mvvm.Services; ``` diff --git a/docs/THEMES.md b/docs/THEMES.md index c498b5d87..4a117926f 100644 --- a/docs/THEMES.md +++ b/docs/THEMES.md @@ -2,18 +2,20 @@ **WPF UI** supports themes. You set the default theme in `App.xaml`, with the help of an automatic resources importer. ```xml - + + ``` -Or, you can add WPF UI resources manually. +Or, you can add **WPF UI** resources manually. ```xml @@ -33,12 +35,12 @@ If you want to change the theme while the application is running, you can call t Wpf.Ui.Appearance.Theme.Apply( Wpf.Ui.Appearance.ThemeType.Light, // Theme type Wpf.Ui.Appearance.BackgroundType.Mica, // Background type - true // Whether to change accents automatically + true // Whether to change accents automatically ); ``` ### Automatic change -The theme can be changed automatically when the operating system changes its background or accent using the [Watcher](https://github.com/lepoco/wpfui/blob/main/WPFUI/Appearance/Watcher.cs) class. +The theme can be changed automatically when the operating system changes its background or accent using the [Watcher](https://github.com/lepoco/wpfui/blob/main/src/Wpf.Ui/Appearance/Watcher.cs) class. ```cpp namespace MyApp { @@ -51,9 +53,9 @@ namespace MyApp Loaded += (sender, args) => { Wpf.Ui.Appearance.Watcher.Watch( - this, // Window class + this, // Window class Wpf.Ui.Appearance.BackgroundType.Mica, // Background type - true // Whether to change accents automatically + true // Whether to change accents automatically ); }; } diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index 24f4ca773..a6a7dbea0 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -5,6 +5,12 @@ - [Visual Studio 2022](https://visualstudio.microsoft.com/vs/community/) - .NET desktop development package _(via VS2022 installer)_ +## Extension +One of the easiest ways to create a new project using *WPF UI* is to use the plug-in for _Visual Studio 2022_. +https://marketplace.visualstudio.com/items?itemName=lepo.wpf-ui + +![wpfui-template](https://user-images.githubusercontent.com/13592821/181920257-1e7bca97-e20c-4324-bf55-d3433a6684a8.png) + ## Get a package The first thing you need to do is install the WPF UI via the package manager. @@ -12,7 +18,8 @@ To do so, in your new WPF project, right-click on **Dependencies** and **Manage Type **WPF-UI** in the search and when the correct result appears - click **Install**. -![image](https://user-images.githubusercontent.com/13592821/158079885-7715b552-bbc6-4574-bac9-92ecb7b161d8.png) +![image](https://user-images.githubusercontent.com/13592821/181920201-892f0e88-39b7-4028-8519-0191532c774d.png) + ## Adding dictionaries @@ -23,11 +30,13 @@ There should be a file called `App.xaml` in your new application. Add new dictio ```xml - + + @@ -45,12 +54,15 @@ At the design stage, we decided not to create ready-made [Window](https://docs.m First, let's modify MainWindow.xaml ```xml - + xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" + Background="{ui:ThemeResource ApplicationBackgroundBrush}" + ExtendsContentIntoTitleBar="True" + WindowBackdropType="Mica" + WindowCornerPreference="Round" + WindowStartupLocation="CenterScreen"> @@ -71,7 +83,7 @@ First, let's modify MainWindow.xaml x:Name="RootNavigation" Grid.Column="0" Margin="6,0,6,0" - Frame="{Binding ElementName=RootFrame}" + Frame="{Binding ElementName=RootFrame, Mode=OneWay}" Navigated="RootNavigation_OnNavigated" SelectedPageIndex="0"> @@ -97,7 +109,7 @@ First, let's modify MainWindow.xaml @@ -111,7 +123,7 @@ First, let's modify MainWindow.xaml HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="24" - Navigation="{Binding ElementName=RootNavigation}" /> + Navigation="{Binding ElementName=RootNavigation, Mode=OneWay}" /> @@ -147,10 +159,11 @@ Things have changed a bit, so let's go over what is what. #### WPF UI Namespace -This line tells the interpreter that we will be using the **WPF UI** controls under the **ui:** abbreviation +This line tells the interpreter that we will be using the **WPF UI** controls under the **ui:** abbreviation. +Additionally, we use a modified `UiWindow` instead of the default window control. ```xml - ``` @@ -159,42 +172,43 @@ This line tells the interpreter that we will be using the **WPF UI** controls un This line informs that in the given directory there are files of our pages. They will be displayed by the navigation. ```xml - ``` -#### Style +#### Mica Background -This line will make the window of our application slightly change. Necessary effects required for the correct display of the custom controls will be added. +Using the modified attributes of the `UiWindow` class, we extend the content of the window to the entire workspace, and then apply the Mica effect for Windows 11 and above. ```xml - + ``` #### Navigation The `ui:NavigationStore` control is responsible managing the displayed pages. The [Page](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.page) is displayed inside the [Frame](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.frame). -As you can see in the example above, the navigation indicates which Frame will display pages. +As you can see in the example below, the navigation indicates which `Frame` will display pages. ```xml + Frame="{Binding ElementName=RootFrame, Mode=OneWay}"/> ``` -### Bradcrumb +### Breadcrumb -Breadcrumb is a small navigation aid, it automatically displays the title of the currently used [Page](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.page) based on its name given in the navigation. As you can see in the example above, Breadcrumb has indicated which navigation it should use +Breadcrumb is a small navigation aid, it automatically displays the title of the currently used [Page](https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.page) based on its name given in the navigation. As you can see in the example above, Breadcrumb has indicated which navigation control it should use ```xml + Navigation="{Binding ElementName=RootNavigation, Mode=OneWay}" /> ``` ### TitleBar From 1b1c835c8e014c257a3bf6e4c5339311ca0354cb Mon Sep 17 00:00:00 2001 From: "filip.vukovinski" Date: Mon, 1 Aug 2022 09:55:51 +0200 Subject: [PATCH 27/90] requested changes --- .../{WpfUi.cs => Controls/ControlsServices.cs} | 10 +++++----- .../Internal/NavigationServiceActivator.cs | 18 +++++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) rename src/Wpf.Ui/{WpfUi.cs => Controls/ControlsServices.cs} (67%) diff --git a/src/Wpf.Ui/WpfUi.cs b/src/Wpf.Ui/Controls/ControlsServices.cs similarity index 67% rename from src/Wpf.Ui/WpfUi.cs rename to src/Wpf.Ui/Controls/ControlsServices.cs index 4b277ce3f..92e46aa44 100644 --- a/src/Wpf.Ui/WpfUi.cs +++ b/src/Wpf.Ui/Controls/ControlsServices.cs @@ -1,14 +1,14 @@ using System; -namespace Wpf.Ui +namespace Wpf.Ui.Controls { /// - /// Used to initialize the library with static values. + /// Used to initialize the library controls with static values. /// - public static class WpfUi + public static class ControlsServices { #if NET48_OR_GREATER || NETCOREAPP3_0_OR_GREATER - internal static IServiceProvider ServiceProvider { get; private set; } + internal static IServiceProvider ControlsServiceProvider { get; private set; } /// /// Accepts a ServiceProvider for configuring dependency injection. @@ -20,7 +20,7 @@ public static void Initialize(IServiceProvider serviceProvider) if (serviceProvider == null) throw new ArgumentNullException(nameof(serviceProvider)); - ServiceProvider = serviceProvider; + ControlsServiceProvider = serviceProvider; } #endif } diff --git a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs index 1c2c77a0c..d9df021f0 100644 --- a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs +++ b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs @@ -8,6 +8,7 @@ using System.Windows; using System.Windows.Controls; using Wpf.Ui.Common; +using Wpf.Ui.Controls; using Wpf.Ui.Controls.Interfaces; namespace Wpf.Ui.Services.Internal; @@ -45,15 +46,16 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) var instance = null as FrameworkElement; #if NET48_OR_GREATER || NETCOREAPP3_0_OR_GREATER - if (WpfUi.ServiceProvider != null) + if (ControlsServices.ControlsServiceProvider != null) { var pageConstructors = pageType.GetConstructors(); var parameterlessCount = pageConstructors.Count(ctor => ctor.GetParameters().Length == 0); var parameterfullCount = pageConstructors.Length - parameterlessCount; if (parameterlessCount == 1) - instance = pageType.GetConstructor(Type.EmptyTypes).Invoke(null) as FrameworkElement; - + { + instance = pageType.GetConstructor(Type.EmptyTypes)!.Invoke(null) as FrameworkElement; + } else if (parameterlessCount == 0 && parameterfullCount > 0) { var maximalCtor = pageConstructors.Select(ctor => @@ -61,7 +63,7 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) var parameters = ctor.GetParameters(); var argumentResolution = parameters.Select(prm => { - var resolved = ResolveArgument(prm.ParameterType, dataContext); + var resolved = ResolveConstructorParameter(prm.ParameterType, dataContext); return resolved != null; }); var fullyResolved = argumentResolution.All(resolved => resolved == true); @@ -82,7 +84,7 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) var arguments = maximalCtor .Constructor.GetParameters() - .Select(prm => ResolveArgument(prm.ParameterType, dataContext)); + .Select(prm => ResolveConstructorParameter(prm.ParameterType, dataContext)); instance = maximalCtor.Constructor.Invoke(arguments.ToArray()) as FrameworkElement; @@ -125,13 +127,15 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) return instance; } - private static object ResolveArgument(Type tParam, object dataContext) +#if NET48_OR_GREATER || NETCOREAPP3_0_OR_GREATER + private static object ResolveConstructorParameter(Type tParam, object dataContext) { if (dataContext != null && dataContext.GetType() == tParam) { return dataContext; } - return WpfUi.ServiceProvider.GetService(tParam); + return ControlsServices.ControlsServiceProvider.GetService(tParam); } +#endif } From 5c3f6dfbbac5f077eeb5a407c25cf4cc30aacbe2 Mon Sep 17 00:00:00 2001 From: "filip.vukovinski" Date: Mon, 1 Aug 2022 09:59:13 +0200 Subject: [PATCH 28/90] exc message fix --- src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs index d9df021f0..38b4a7627 100644 --- a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs +++ b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs @@ -80,7 +80,7 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) .FirstOrDefault(); if (maximalCtor == null) - throw new InvalidOperationException($"The {pageType} page does not have a parameterless constructor or the required services have not been configured for dependency injection. Use the static WpfUi class to initialize the GUI library with your service provider. If you are using {typeof(Mvvm.Contracts.IPageService)} do not navigate initially and don't use Cache or Precache."); + throw new InvalidOperationException($"The {pageType} page does not have a parameterless constructor or the required services have not been configured for dependency injection. Use the static {nameof(ControlsServices)} class to initialize the GUI library with your service provider. If you are using {typeof(Mvvm.Contracts.IPageService)} do not navigate initially and don't use Cache or Precache."); var arguments = maximalCtor .Constructor.GetParameters() From 36de5bdf59cc6d33f0e64f37617a133dd21c0d09 Mon Sep 17 00:00:00 2001 From: "filip.vukovinski" Date: Tue, 2 Aug 2022 11:31:35 +0200 Subject: [PATCH 29/90] refactored out some methods --- .../Internal/NavigationServiceActivator.cs | 129 +++++++++++------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs index 38b4a7627..3bc46b9da 100644 --- a/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs +++ b/src/Wpf.Ui/Services/Internal/NavigationServiceActivator.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Windows; using System.Windows.Controls; +using System.Reflection; using Wpf.Ui.Common; using Wpf.Ui.Controls; using Wpf.Ui.Controls.Interfaces; @@ -54,76 +55,35 @@ public static FrameworkElement CreateInstance(Type pageType, object dataContext) if (parameterlessCount == 1) { - instance = pageType.GetConstructor(Type.EmptyTypes)!.Invoke(null) as FrameworkElement; + instance = InvokeParameterlessConstructor(pageType); } else if (parameterlessCount == 0 && parameterfullCount > 0) { - var maximalCtor = pageConstructors.Select(ctor => - { - var parameters = ctor.GetParameters(); - var argumentResolution = parameters.Select(prm => - { - var resolved = ResolveConstructorParameter(prm.ParameterType, dataContext); - return resolved != null; - }); - var fullyResolved = argumentResolution.All(resolved => resolved == true); - var score = fullyResolved ? parameters.Length : 0; - - return score == 0 ? null : new - { - Constructor = ctor, - Score = score - }; - }) - .Where(cs => cs != null) - .OrderBy(cs => cs.Score) - .FirstOrDefault(); - - if (maximalCtor == null) + var selectedCtor = FitBestConstructor(pageConstructors, dataContext); + if (selectedCtor == null) throw new InvalidOperationException($"The {pageType} page does not have a parameterless constructor or the required services have not been configured for dependency injection. Use the static {nameof(ControlsServices)} class to initialize the GUI library with your service provider. If you are using {typeof(Mvvm.Contracts.IPageService)} do not navigate initially and don't use Cache or Precache."); - var arguments = maximalCtor - .Constructor.GetParameters() - .Select(prm => ResolveConstructorParameter(prm.ParameterType, dataContext)); - - instance = maximalCtor.Constructor.Invoke(arguments.ToArray()) as FrameworkElement; - - if (dataContext != null) - instance!.DataContext = dataContext; - + instance = InvokeElementConstructor(selectedCtor, dataContext); + SetDataContext(instance, dataContext); return instance; } } else if (dataContext != null) - { - var dataContextConstructor = pageType.GetConstructor(new[] { dataContext.GetType() }); - - // Return instance which has constructor with matching datacontext type - if (dataContextConstructor != null) - return dataContextConstructor.Invoke(new[] { dataContext }) as FrameworkElement; - } #else - // Very poor dependency injection if (dataContext != null) +#endif { - var dataContextConstructor = pageType.GetConstructor(new[] { dataContext.GetType() }); - - // Return instance which has constructor with matching datacontext type - if (dataContextConstructor != null) - return dataContextConstructor.Invoke(new[] { dataContext }) as FrameworkElement; + instance = InvokeElementConstructor(pageType, dataContext); + if (instance != null) + return instance; } -#endif - - var emptyConstructor = pageType.GetConstructor(Type.EmptyTypes); + var emptyConstructor = FindParameterlessConstructor(pageType); if (emptyConstructor == null) throw new InvalidOperationException($"The {pageType} page does not have a parameterless constructor. If you are using {typeof(Mvvm.Contracts.IPageService)} do not navigate initially and don't use Cache or Precache."); instance = emptyConstructor.Invoke(null) as FrameworkElement; - - if (dataContext != null) - instance!.DataContext = dataContext; - + SetDataContext(instance, dataContext); return instance; } @@ -137,5 +97,70 @@ private static object ResolveConstructorParameter(Type tParam, object dataContex return ControlsServices.ControlsServiceProvider.GetService(tParam); } + + /// + /// Picks a constructor which has the most satisfiable arguments count. + /// + /// + /// + /// + private static ConstructorInfo FitBestConstructor(ConstructorInfo[] parameterfullCtors, object dataContext) + { + return parameterfullCtors.Select(ctor => + { + var parameters = ctor.GetParameters(); + var argumentResolution = parameters.Select(prm => + { + var resolved = ResolveConstructorParameter(prm.ParameterType, dataContext); + return resolved != null; + }); + var fullyResolved = argumentResolution.All(resolved => resolved == true); + var score = fullyResolved ? parameters.Length : 0; + + return score == 0 ? null : new + { + Constructor = ctor, + Score = score + }; + }) + .Where(cs => cs != null) + .OrderBy(cs => cs.Score) + .FirstOrDefault()?.Constructor; + } + + private static FrameworkElement InvokeElementConstructor(ConstructorInfo ctor, object dataContext) + { + var args = ctor + .GetParameters() + .Select(prm => + ResolveConstructorParameter(prm.ParameterType, dataContext)); + + return ctor.Invoke(args.ToArray()) as FrameworkElement; + } #endif + + private static FrameworkElement InvokeElementConstructor(Type tPage, object dataContext) + { + var ctor = tPage.GetConstructor(new[] { dataContext.GetType() }); + if (ctor != null) + return ctor.Invoke(new[] { dataContext }) as FrameworkElement; + + return null; + } + + private static ConstructorInfo FindParameterlessConstructor(Type tPage) + { + return tPage.GetConstructor(Type.EmptyTypes); + } + + private static FrameworkElement InvokeParameterlessConstructor(Type tPage) + { + return FindParameterlessConstructor(tPage)?.Invoke(null) as FrameworkElement; + } + + private static void SetDataContext(FrameworkElement element, object dataContext) + { + if (dataContext != null) + element.DataContext = dataContext; + } } From 86cec3dcade21f9ff5b1467df14506a102e50cea Mon Sep 17 00:00:00 2001 From: Tinekk <11279290+Tinekk@users.noreply.github.com> Date: Tue, 2 Aug 2022 13:04:52 +0200 Subject: [PATCH 30/90] Fix closing tag --- docs/TUTORIAL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md index 24f4ca773..220da606d 100644 --- a/docs/TUTORIAL.md +++ b/docs/TUTORIAL.md @@ -139,7 +139,7 @@ First, let's modify MainWindow.xaml - + ``` From a2857ac66ea5ff35078861a0ab5599a37d07b742 Mon Sep 17 00:00:00 2001 From: pomianowski Date: Thu, 4 Aug 2022 18:14:45 +0200 Subject: [PATCH 31/90] Fix IsThreeState in `CheckBox` [#213] --- src/Wpf.Ui.Demo/Views/Pages/Input.xaml | 4 ++- src/Wpf.Ui/Styles/Controls/CheckBox.xaml | 45 +++++++++++++----------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/Wpf.Ui.Demo/Views/Pages/Input.xaml b/src/Wpf.Ui.Demo/Views/Pages/Input.xaml index 111a3034a..b71e953d5 100644 --- a/src/Wpf.Ui.Demo/Views/Pages/Input.xaml +++ b/src/Wpf.Ui.Demo/Views/Pages/Input.xaml @@ -376,7 +376,9 @@ + IsChecked="True" + IsEnabled="False" + IsThreeState="True" /> <CheckBox IsChecked="True" /> diff --git a/src/Wpf.Ui/Styles/Controls/CheckBox.xaml b/src/Wpf.Ui/Styles/Controls/CheckBox.xaml index 70f2f8222..9ddec3c5f 100644 --- a/src/Wpf.Ui/Styles/Controls/CheckBox.xaml +++ b/src/Wpf.Ui/Styles/Controls/CheckBox.xaml @@ -93,22 +93,6 @@ - - - - - - - @@ -126,10 +110,14 @@ - - - - + + + + + + + + @@ -146,6 +134,17 @@ + + + + + + + + + + + @@ -157,6 +156,12 @@ + + + + + + From fa7d1254ded47af166006eca4dca9a8d031d5187 Mon Sep 17 00:00:00 2001 From: JeremyWu917 <1280442096@qq.com> Date: Sat, 6 Aug 2022 23:49:46 +0800 Subject: [PATCH 32/90] Fix issues #334 --- src/Wpf.Ui.Demo/Views/Pages/Data.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Wpf.Ui.Demo/Views/Pages/Data.xaml b/src/Wpf.Ui.Demo/Views/Pages/Data.xaml index 1f1d5f730..e7e751eab 100644 --- a/src/Wpf.Ui.Demo/Views/Pages/Data.xaml +++ b/src/Wpf.Ui.Demo/Views/Pages/Data.xaml @@ -50,7 +50,7 @@ Text="Default ListView" /> <ListView ItemsSource="{Binding ListBoxItemCollection}" SelectedIndex="0"/> From 13c7c7bc4a702a4b6ae4dc565b945d7495554c8f Mon Sep 17 00:00:00 2001 From: JeremyWu917 <1280442096@qq.com> Date: Sun, 7 Aug 2022 00:08:12 +0800 Subject: [PATCH 33/90] Fix issues #333 --- src/Wpf.Ui.Demo/Models/Data/Customer.cs | 1 + src/Wpf.Ui.Demo/ViewModels/DataViewModel.cs | 6 ++++++ src/Wpf.Ui.Demo/Views/Pages/Data.xaml | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Wpf.Ui.Demo/Models/Data/Customer.cs b/src/Wpf.Ui.Demo/Models/Data/Customer.cs index 0247bc57c..2a101d2ab 100644 --- a/src/Wpf.Ui.Demo/Models/Data/Customer.cs +++ b/src/Wpf.Ui.Demo/Models/Data/Customer.cs @@ -10,6 +10,7 @@ public class Customer public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } + public string MailTo { get; set; } public bool IsMember { get; set; } public OrderStatus Status { get; set; } } diff --git a/src/Wpf.Ui.Demo/ViewModels/DataViewModel.cs b/src/Wpf.Ui.Demo/ViewModels/DataViewModel.cs index 2cbd7cc13..8c9281b1f 100644 --- a/src/Wpf.Ui.Demo/ViewModels/DataViewModel.cs +++ b/src/Wpf.Ui.Demo/ViewModels/DataViewModel.cs @@ -65,6 +65,7 @@ private void InitializeData() new() { Email = "john.doe@example.com", + MailTo = "mailto:john.doe@example.com", FirstName = "John", LastName = "Doe", IsMember = true, @@ -73,6 +74,7 @@ private void InitializeData() new() { Email = "chloe.clarkson@example.com", + MailTo = "mailto:chloe.clarkson@example.com", FirstName = "Chloe", LastName = "Clarkson", IsMember = true, @@ -81,6 +83,7 @@ private void InitializeData() new() { Email = "eric.brown@example.com", + MailTo = "mailto:eric.brown@example.com", FirstName = "Eric", LastName = "Brown", IsMember = false, @@ -89,6 +92,7 @@ private void InitializeData() new() { Email = "john.doe@example.com", + MailTo = "mailto:john.doe@example.com", FirstName = "John", LastName = "Doe", IsMember = true, @@ -97,6 +101,7 @@ private void InitializeData() new() { Email = "chloe.clarkson@example.com", + MailTo = "mailto:chloe.clarkson@example.com", FirstName = "Chloe", LastName = "Clarkson", IsMember = true, @@ -105,6 +110,7 @@ private void InitializeData() new() { Email = "eric.brown@example.com", + MailTo = "mailto:eric.brown@example.com", FirstName = "Eric", LastName = "Brown", IsMember = false, diff --git a/src/Wpf.Ui.Demo/Views/Pages/Data.xaml b/src/Wpf.Ui.Demo/Views/Pages/Data.xaml index e7e751eab..ec29e8154 100644 --- a/src/Wpf.Ui.Demo/Views/Pages/Data.xaml +++ b/src/Wpf.Ui.Demo/Views/Pages/Data.xaml @@ -125,7 +125,7 @@ From 529a3bdcd0bbd5f83c4f89d1d801bc7af384e3f6 Mon Sep 17 00:00:00 2001 From: walterlv Date: Wed, 10 Aug 2022 20:11:58 +0800 Subject: [PATCH 34/90] Fix TreeView virtualization. --- src/Wpf.Ui/Styles/Controls/TreeView.xaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Wpf.Ui/Styles/Controls/TreeView.xaml b/src/Wpf.Ui/Styles/Controls/TreeView.xaml index 429e5f0c6..913617d96 100644 --- a/src/Wpf.Ui/Styles/Controls/TreeView.xaml +++ b/src/Wpf.Ui/Styles/Controls/TreeView.xaml @@ -46,6 +46,17 @@ + + + + + + + + + + + + + diff --git a/src/Wpf.Ui/Styles/Wpf.Ui.xaml b/src/Wpf.Ui/Styles/Wpf.Ui.xaml index f1258ed10..5080700e4 100644 --- a/src/Wpf.Ui/Styles/Wpf.Ui.xaml +++ b/src/Wpf.Ui/Styles/Wpf.Ui.xaml @@ -4,10 +4,9 @@ Copyright (C) Leszek Pomianowski and WPF UI Contributors. All Rights Reserved. --> - + @@ -43,6 +42,7 @@ + From 2a7e1ebfca7200bbe7747c3384ee5050a7e0126b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Tue, 20 Sep 2022 18:47:49 +0200 Subject: [PATCH 66/90] features/InfoBar: wip --- src/Wpf.Ui.Demo/Views/Pages/Controls.xaml | 5 +++-- src/Wpf.Ui/Controls/InfoBar.cs | 18 +++++++++++---- src/Wpf.Ui/Controls/InfoBarSeverity.cs | 27 +++++++++++++++++++++++ src/Wpf.Ui/Styles/Controls/InfoBar.xaml | 16 +++++++++----- 4 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 src/Wpf.Ui/Controls/InfoBarSeverity.cs diff --git a/src/Wpf.Ui.Demo/Views/Pages/Controls.xaml b/src/Wpf.Ui.Demo/Views/Pages/Controls.xaml index f143c865d..ab5633318 100644 --- a/src/Wpf.Ui.Demo/Views/Pages/Controls.xaml +++ b/src/Wpf.Ui.Demo/Views/Pages/Controls.xaml @@ -299,9 +299,10 @@ - + Message="Renew your subscription to keep all functionality" + Severity="Warning" /> (string)GetValue(MessageProperty); - set => SetValue(MessageProperty, value); + get { return (string)GetValue(MessageProperty); } + set { SetValue(MessageProperty, value); } + } + + public InfoBarSeverity Severity + { + get { return (InfoBarSeverity)GetValue(SeverityProperty); } + set { SetValue(SeverityProperty, value); } } public string Title { - get => (string)GetValue(TitleProperty); - set => SetValue(TitleProperty, value); + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } } } } diff --git a/src/Wpf.Ui/Controls/InfoBarSeverity.cs b/src/Wpf.Ui/Controls/InfoBarSeverity.cs new file mode 100644 index 000000000..4171015e7 --- /dev/null +++ b/src/Wpf.Ui/Controls/InfoBarSeverity.cs @@ -0,0 +1,27 @@ +namespace Wpf.Ui.Controls +{ + public enum InfoBarSeverity + { + /// + /// Communicates that the InfoBar is displaying general information that requires the user's attention. + /// + Informational = 0, + + /// + /// Communicates that the InfoBar is displaying information regarding a long-running and/or background task + /// that has completed successfully. + /// + Success = 1, + + /// + /// Communicates that the InfoBar is displaying information regarding a condition that might cause a problem in + /// the future. + /// + Warning = 2, + + /// + /// Communicates that the InfoBar is displaying information regarding an error or problem that has occurred. + /// + Error = 3 + } +} diff --git a/src/Wpf.Ui/Styles/Controls/InfoBar.xaml b/src/Wpf.Ui/Styles/Controls/InfoBar.xaml index 3de9aed05..29d0d5c18 100644 --- a/src/Wpf.Ui/Styles/Controls/InfoBar.xaml +++ b/src/Wpf.Ui/Styles/Controls/InfoBar.xaml @@ -27,11 +27,17 @@ - + + + + + From f83e904864fa0c16b02fcc8dd2127ca0f1fb2ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Wed, 21 Sep 2022 10:36:42 +0200 Subject: [PATCH 67/90] features/InfoBar: styling further along --- src/Wpf.Ui/Styles/Controls/InfoBar.xaml | 50 +++++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Wpf.Ui/Styles/Controls/InfoBar.xaml b/src/Wpf.Ui/Styles/Controls/InfoBar.xaml index 29d0d5c18..b839ee84d 100644 --- a/src/Wpf.Ui/Styles/Controls/InfoBar.xaml +++ b/src/Wpf.Ui/Styles/Controls/InfoBar.xaml @@ -9,6 +9,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Wpf.Ui.Controls"> + 14,16,14,16 + 1 + - - - - - + + + + + + + + + + + + + #FFFF0000 + + 11,5,11,6 + 1 + 8,0,0,0 + 14 + 22 + 22 + + + + + + + +