From 002b59c3e4aef2a6a80d7547c98b8c2f6069e23d Mon Sep 17 00:00:00 2001 From: pomianowski <13592821+pomianowski@users.noreply.github.com> Date: Sat, 19 Aug 2023 14:40:07 +0200 Subject: [PATCH 01/23] Fix null exception when binding AutoSuggestBox before initialization #731 --- src/Wpf.Ui.Gallery/App.xaml.cs | 3 +- .../Pages/Windows/WindowsViewModel.cs | 11 +++- .../Windows/SandboxWindowViewModel.cs | 11 ++++ .../Views/Windows/SandboxWindow.xaml | 49 ++++++++++++++ .../Views/Windows/SandboxWindow.xaml.cs | 27 ++++++++ .../Controls/AutoSuggestBox/AutoSuggestBox.cs | 64 +++++++++++-------- 6 files changed, 134 insertions(+), 31 deletions(-) create mode 100644 src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs create mode 100644 src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml create mode 100644 src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs diff --git a/src/Wpf.Ui.Gallery/App.xaml.cs b/src/Wpf.Ui.Gallery/App.xaml.cs index 6e2c95309..8e121fc8e 100644 --- a/src/Wpf.Ui.Gallery/App.xaml.cs +++ b/src/Wpf.Ui.Gallery/App.xaml.cs @@ -27,10 +27,9 @@ public partial class App c.SetBasePath(AppContext.BaseDirectory); }) .ConfigureServices( - (context, services) => + (_, services) => { // App Host - services.AddHostedService(); // Main window container with navigation diff --git a/src/Wpf.Ui.Gallery/ViewModels/Pages/Windows/WindowsViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Pages/Windows/WindowsViewModel.cs index 51991c57c..4f0576a22 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Pages/Windows/WindowsViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Pages/Windows/WindowsViewModel.cs @@ -18,7 +18,10 @@ public partial class WindowsViewModel : ObservableObject private IEnumerable _windowCards = new WindowCard[] { new("Monaco", "Visual Studio Code in your WPF app.", SymbolRegular.CodeBlock24, "monaco"), - new("Editor", "Text editor with tabbed background.", SymbolRegular.ScanText24, "editor") + new("Editor", "Text editor with tabbed background.", SymbolRegular.ScanText24, "editor"), +#if DEBUG + new("Sandbox", "Sandbox for controls testing.", SymbolRegular.ScanText24, "sandbox"), +#endif }; public WindowsViewModel(WindowsProviderService windowsProviderService) @@ -30,7 +33,9 @@ public WindowsViewModel(WindowsProviderService windowsProviderService) public void OnOpenWindow(string value) { if (String.IsNullOrEmpty(value)) + { return; + } switch (value) { @@ -41,6 +46,10 @@ public void OnOpenWindow(string value) case "editor": _windowsProviderService.Show(); break; + + case "sandbox": + _windowsProviderService.Show(); + break; } } } diff --git a/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs new file mode 100644 index 000000000..9dfb5c72d --- /dev/null +++ b/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Gallery.ViewModels.Windows; +public partial class SandboxWindowViewModel : ObservableObject +{ + [ObservableProperty] + public string? _autoSuggestBoxText; +} diff --git a/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml new file mode 100644 index 000000000..ae4030e14 --- /dev/null +++ b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs new file mode 100644 index 000000000..8d44bb42f --- /dev/null +++ b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs @@ -0,0 +1,27 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using Wpf.Ui.Controls; +using Wpf.Ui.Gallery.ViewModels.Windows; + +namespace Wpf.Ui.Gallery.Views.Windows; + +public partial class SandboxWindow +{ + public SandboxWindowViewModel ViewModel { get; init; } + + public SandboxWindow(SandboxWindowViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + } + + private void OnAutoSuggestBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) + { + Debug.WriteLine($"OnAutoSuggestBoxTextChanged: {sender.Text} (ViewModel.AutoSuggestBoxText: {ViewModel.AutoSuggestBoxText})"); + } +} diff --git a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs index 260947b97..c16971949 100644 --- a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs +++ b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs @@ -69,7 +69,7 @@ public class AutoSuggestBox : System.Windows.Controls.ItemsControl, IIconControl nameof(Text), typeof(string), typeof(AutoSuggestBox), - new PropertyMetadata(string.Empty, TextPropertyChangedCallback) + new PropertyMetadata(String.Empty, TextPropertyChangedCallback) ); /// @@ -79,7 +79,7 @@ public class AutoSuggestBox : System.Windows.Controls.ItemsControl, IIconControl nameof(PlaceholderText), typeof(string), typeof(AutoSuggestBox), - new PropertyMetadata(string.Empty) + new PropertyMetadata(String.Empty) ); /// @@ -125,7 +125,7 @@ public class AutoSuggestBox : System.Windows.Controls.ItemsControl, IIconControl ); /// - /// Set your items here if you want to use the default filtering + /// Gets or sets your items here if you want to use the default filtering /// public IList OriginalItemsSource { @@ -134,7 +134,7 @@ public IList OriginalItemsSource } /// - /// Gets or sets a Boolean value indicating whether the drop-down portion of the is open. + /// Gets or sets a value indicating whether the drop-down portion of the is open. /// public bool IsSuggestionListOpen { @@ -143,7 +143,7 @@ public bool IsSuggestionListOpen } /// - /// Gets or sets the text that is shown in the control + /// Gets or sets the text that is shown in the control. /// /// /// This property is not typically set in XAML. @@ -167,7 +167,7 @@ public string PlaceholderText } /// - /// Gets or set the maximum height for the drop-down portion of the control. + /// Gets or sets the maximum height for the drop-down portion of the control. /// public double MaxSuggestionListHeight { @@ -189,12 +189,12 @@ public bool UpdateTextOnSelect /// public IconElement? Icon { - get => (IconElement)GetValue(IconProperty); + get => (IconElement?)GetValue(IconProperty); set => SetValue(IconProperty, value); } /// - /// Used for focusing control + /// Gets command used for focusing control. /// public ICommand FocusCommand => (ICommand)GetValue(FocusCommandProperty); @@ -261,7 +261,7 @@ public event TypedEventHandler RemoveHandler(TextChangedEvent, value); } - protected TextBox TextBox = null!; + protected TextBox? TextBox = null; protected Popup SuggestionsPopup = null!; @@ -342,7 +342,7 @@ protected virtual void ReleaseTemplateResources() /// /// Method for . /// - /// + /// Currently submitted query text. protected virtual void OnQuerySubmitted(string queryText) { var args = new AutoSuggestBoxQuerySubmittedEventArgs(QuerySubmittedEvent, this) @@ -356,7 +356,7 @@ protected virtual void OnQuerySubmitted(string queryText) /// /// Method for . /// - /// + /// Currently selected item. protected virtual void OnSuggestionChosen(object selectedItem) { var args = new AutoSuggestBoxSuggestionChosenEventArgs(SuggestionChosenEvent, this) @@ -375,8 +375,8 @@ protected virtual void OnSuggestionChosen(object selectedItem) /// /// Method for . /// - /// - /// + /// Data for the text changed event. + /// Changed text. protected virtual void OnTextChanged(AutoSuggestionBoxTextChangeReason reason, string text) { var args = new AutoSuggestBoxTextChangedEventArgs(TextChangedEvent, this) @@ -397,14 +397,14 @@ private void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key is Key.Escape) { - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); return; } if (e.Key is Key.Enter) { - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); OnQuerySubmitted(TextBox.Text); @@ -416,7 +416,7 @@ private void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs e) return; } - SuggestionsList.Focus(); + _ = SuggestionsList.Focus(); } private void TextBoxOnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) @@ -426,7 +426,7 @@ private void TextBoxOnLostKeyboardFocus(object sender, KeyboardFocusChangedEvent return; } - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); } private void TextBoxOnTextChanged(object sender, TextChangedEventArgs e) @@ -446,14 +446,14 @@ private void TextBoxOnTextChanged(object sender, TextChangedEventArgs e) OnTextChanged(changeReason, TextBox.Text); - SuggestionsList.SelectedItem = null; + SuggestionsList.SetCurrentValue(Selector.SelectedItemProperty, null); if (changeReason is not AutoSuggestionBoxTextChangeReason.UserInput) { return; } - IsSuggestionListOpen = true; + SetCurrentValue(IsSuggestionListOpenProperty, true); } private void SuggestionsListOnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) @@ -463,7 +463,7 @@ private void SuggestionsListOnLostKeyboardFocus(object sender, KeyboardFocusChan return; } - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); } private void SuggestionsListOnPreviewKeyDown(object sender, KeyEventArgs e) @@ -473,7 +473,7 @@ private void SuggestionsListOnPreviewKeyDown(object sender, KeyEventArgs e) return; } - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); OnSelectedChanged(SuggestionsList.SelectedItem); } @@ -485,7 +485,7 @@ private void SuggestionsListOnPreviewMouseLeftButtonUp(object sender, MouseButto return; } - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); if (_selectedItem is not null) { @@ -514,7 +514,7 @@ private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool if (message is User32.WM.NCACTIVATE or User32.WM.WINDOWPOSCHANGED) { - IsSuggestionListOpen = false; + SetCurrentValue(IsSuggestionListOpenProperty, false); } return IntPtr.Zero; @@ -531,7 +531,8 @@ private void UpdateTexBoxTextAfterSelection(object selectedObj) { _changingTextAfterSuggestionChosen = true; - TextBox.Text = GetStringFromObj(selectedObj); + TextBox.SetCurrentValue(System.Windows.Controls.TextBox.TextProperty, GetStringFromObj(selectedObj)); + _changingTextAfterSuggestionChosen = false; } @@ -539,7 +540,7 @@ private void DefaultFiltering(string text) { if (String.IsNullOrEmpty(text)) { - ItemsSource = OriginalItemsSource; + SetCurrentValue(ItemsSourceProperty, OriginalItemsSource); return; } @@ -560,10 +561,10 @@ private void DefaultFiltering(string text) } } - ItemsSource = suitableItems; + SetCurrentValue(ItemsSourceProperty, suitableItems); } - private string GetStringFromObj(object obj) + private string? GetStringFromObj(object obj) { var text = String.Empty; @@ -592,13 +593,20 @@ DependencyPropertyChangedEventArgs e var self = (AutoSuggestBox)d; var newText = (string)e.NewValue; + if (self.TextBox is null) + { + return; + } + if (self.TextBox.Text == newText) { return; } self._isChangedTextOutSideOfTextBox = true; - self.TextBox.Text = newText; + + self.TextBox.SetCurrentValue(System.Windows.Controls.TextBox.TextProperty, newText); + self._isChangedTextOutSideOfTextBox = false; } } From 438edf803bb21f15f747ef48d47645f0b72d1338 Mon Sep 17 00:00:00 2001 From: pomianowski <13592821+pomianowski@users.noreply.github.com> Date: Sat, 26 Aug 2023 10:38:15 +0200 Subject: [PATCH 02/23] Drop Moq due to security leak risk https://github.com/moq/moq/issues/1396 --- Directory.Packages.props | 8 ++++---- .../ViewModels/Windows/SandboxWindowViewModel.cs | 1 + .../Wpf.Ui.Gallery.UnitTests.csproj | 2 +- .../Animations/TransitionAnimationProviderTests.cs | 4 ++-- tests/Wpf.Ui.UnitTests/Usings.cs | 2 +- tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index b5a282e71..af80ca323 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,14 +11,14 @@ - + - + - + - \ No newline at end of file + diff --git a/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs b/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs index 9dfb5c72d..57011bb4a 100644 --- a/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs +++ b/src/Wpf.Ui.Gallery/ViewModels/Windows/SandboxWindowViewModel.cs @@ -4,6 +4,7 @@ // All Rights Reserved. namespace Wpf.Ui.Gallery.ViewModels.Windows; + public partial class SandboxWindowViewModel : ObservableObject { [ObservableProperty] diff --git a/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj b/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj index f8be20445..cc2600669 100644 --- a/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj +++ b/tests/Wpf.Ui.Gallery.UnitTests/Wpf.Ui.Gallery.UnitTests.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Wpf.Ui.UnitTests/Animations/TransitionAnimationProviderTests.cs b/tests/Wpf.Ui.UnitTests/Animations/TransitionAnimationProviderTests.cs index bd8fb6484..2007d3bce 100644 --- a/tests/Wpf.Ui.UnitTests/Animations/TransitionAnimationProviderTests.cs +++ b/tests/Wpf.Ui.UnitTests/Animations/TransitionAnimationProviderTests.cs @@ -12,9 +12,9 @@ public class TransitionAnimationProviderTests [Fact] public void ApplyTransition_ReturnsFalse_WhenDurationIsLessThan10() { - var mockedUiElement = new Mock(); + var mockedUiElement = Substitute.For(); - var result = TransitionAnimationProvider.ApplyTransition(mockedUiElement.Object, Transition.FadeIn, -10); + var result = TransitionAnimationProvider.ApplyTransition(mockedUiElement, Transition.FadeIn, -10); Assert.False(result); } diff --git a/tests/Wpf.Ui.UnitTests/Usings.cs b/tests/Wpf.Ui.UnitTests/Usings.cs index f971b3f32..047ddaba9 100644 --- a/tests/Wpf.Ui.UnitTests/Usings.cs +++ b/tests/Wpf.Ui.UnitTests/Usings.cs @@ -3,7 +3,7 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -global using Moq; +global using NSubstitute; global using System; global using System.Windows; global using Xunit; diff --git a/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj b/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj index b22e63047..e868c0589 100644 --- a/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj +++ b/tests/Wpf.Ui.UnitTests/Wpf.Ui.UnitTests.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive From fd11ebef11eb8e92d7d62ff716df58961d567178 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 23:09:00 +0000 Subject: [PATCH 03/23] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/wpf-ui-cd-docs.yaml | 2 +- .github/workflows/wpf-ui-cd-extension.yaml | 2 +- .github/workflows/wpf-ui-cd-nuget.yaml | 2 +- .github/workflows/wpf-ui-pr-validator.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wpf-ui-cd-docs.yaml b/.github/workflows/wpf-ui-cd-docs.yaml index 17f18ce99..94541ed45 100644 --- a/.github/workflows/wpf-ui-cd-docs.yaml +++ b/.github/workflows/wpf-ui-cd-docs.yaml @@ -26,7 +26,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v3 - name: Use Node.js 18.x diff --git a/.github/workflows/wpf-ui-cd-extension.yaml b/.github/workflows/wpf-ui-cd-extension.yaml index c400a5698..4850004c4 100644 --- a/.github/workflows/wpf-ui-cd-extension.yaml +++ b/.github/workflows/wpf-ui-cd-extension.yaml @@ -10,7 +10,7 @@ jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v1.3 with: msbuild-architecture: x64 diff --git a/.github/workflows/wpf-ui-cd-nuget.yaml b/.github/workflows/wpf-ui-cd-nuget.yaml index 51e13cdbc..65427fbe8 100644 --- a/.github/workflows/wpf-ui-cd-nuget.yaml +++ b/.github/workflows/wpf-ui-cd-nuget.yaml @@ -10,7 +10,7 @@ jobs: deploy: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v1.3 with: msbuild-architecture: x64 diff --git a/.github/workflows/wpf-ui-pr-validator.yaml b/.github/workflows/wpf-ui-pr-validator.yaml index ed21ffcf8..b8f337907 100644 --- a/.github/workflows/wpf-ui-pr-validator.yaml +++ b/.github/workflows/wpf-ui-pr-validator.yaml @@ -12,7 +12,7 @@ jobs: build: runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: microsoft/setup-msbuild@v1.3 with: msbuild-architecture: x64 From d5621a1bd544439c13c76c6712aa75724baa7c09 Mon Sep 17 00:00:00 2001 From: MakesYT <42534870+MakesYT@users.noreply.github.com> Date: Tue, 5 Sep 2023 13:15:54 +0800 Subject: [PATCH 04/23] Optimizes the WindowBackdrop Settings before version 22H1 Make IconSourceElementConverter to public --- src/Wpf.Ui/Controls/Window/WindowBackdrop.cs | 6 +----- src/Wpf.Ui/Converters/IconSourceElementConverter.cs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs b/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs index 86d0a114a..c19078d11 100644 --- a/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs +++ b/src/Wpf.Ui/Controls/Window/WindowBackdrop.cs @@ -90,12 +90,8 @@ public static bool ApplyBackdrop(IntPtr hWnd, WindowBackdropType backdropType) // 22H1 if (!Win32.Utilities.IsOSWindows11Insider1OrNewer) { - if (backdropType == WindowBackdropType.Mica || backdropType == WindowBackdropType.Auto) + if (backdropType != WindowBackdropType.None ) return ApplyLegacyMicaBackdrop(hWnd); - - if (backdropType == WindowBackdropType.Acrylic) - return ApplyLegacyAcrylicBackdrop(hWnd); - return false; } diff --git a/src/Wpf.Ui/Converters/IconSourceElementConverter.cs b/src/Wpf.Ui/Converters/IconSourceElementConverter.cs index d50bbb5d1..fecbbc2f6 100644 --- a/src/Wpf.Ui/Converters/IconSourceElementConverter.cs +++ b/src/Wpf.Ui/Converters/IconSourceElementConverter.cs @@ -8,7 +8,7 @@ namespace Wpf.Ui.Converters; -internal class IconSourceElementConverter : IValueConverter +public class IconSourceElementConverter : IValueConverter { public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { From 9bfe4720febaf1c16daa89e753bdff771ae852cc Mon Sep 17 00:00:00 2001 From: pomianowski <13592821+pomianowski@users.noreply.github.com> Date: Tue, 5 Sep 2023 23:19:34 +0200 Subject: [PATCH 05/23] Update `DropDownButton` `Snackbar` and `SplitButton` --- docs/templates/wpfui/src/wpfui.scss | 23 +- src/Wpf.Ui.Gallery/AssemblyInfo.cs | 8 +- .../Services/ApplicationHostService.cs | 32 ++- .../Services/Contracts/IWindow.cs | 2 + src/Wpf.Ui.Gallery/Usings.cs | 2 +- .../Pages/BasicInput/DropDownButtonPage.xaml | 4 +- .../Pages/BasicInput/SplitButtonPage.xaml | 8 +- .../Views/Windows/MainWindow.xaml.cs | 2 +- .../Views/Windows/SandboxWindow.xaml.cs | 9 +- .../Controls/AutoSuggestBox/AutoSuggestBox.cs | 5 +- .../Controls/DropDownButton/DropDownButton.cs | 149 +++---------- .../DropDownButton/DropDownButton.xaml | 199 ++++-------------- src/Wpf.Ui/Controls/Menu/MenuItem.xaml | 2 +- .../NavigationView.Properties.cs | 78 +++++-- src/Wpf.Ui/Controls/Snackbar/Snackbar.xaml | 6 +- .../Controls/SplitButton/SplitButton.cs | 83 +++----- .../Controls/SplitButton/SplitButton.xaml | 196 ++++++----------- src/Wpf.Ui/Controls/Window/WindowBackdrop.cs | 78 +++++-- ...ckButtonVisibilityToVisibilityConverter.cs | 7 +- .../Converters/BoolToVisibilityConverter.cs | 7 +- .../Converters/BrushToColorConverter.cs | 7 +- .../Converters/FallbackBrushConverter.cs | 7 +- .../LeftSplitCornerRadiusConverter.cs | 7 +- .../Converters/LeftSplitThicknessConverter.cs | 7 +- .../Converters/ProgressThicknessConverter.cs | 7 +- .../RightSplitCornerRadiusConverter.cs | 7 +- .../RightSplitThicknessConverter.cs | 7 +- .../Converters/TextToAsteriskConverter.cs | 7 +- src/Wpf.Ui/Interop/User32.cs | 10 +- src/Wpf.Ui/Resources/Theme/Light.xaml | 4 +- src/Wpf.Ui/SnackbarService.cs | 8 +- .../TransitionAnimationProviderTests.cs | 6 +- 32 files changed, 370 insertions(+), 614 deletions(-) diff --git a/docs/templates/wpfui/src/wpfui.scss b/docs/templates/wpfui/src/wpfui.scss index c9246a002..b46aef970 100644 --- a/docs/templates/wpfui/src/wpfui.scss +++ b/docs/templates/wpfui/src/wpfui.scss @@ -38,6 +38,13 @@ h5 { rgb(19, 104, 145) 50%, rgb(32, 135, 135) 75% ); + transition: background-position 0.5s ease-in-out; + background-size: 200% 200%; + background-position: 0% 0%; + + &:hover { + background-position: 100% 100%; + } } .btn-colorful { @@ -48,16 +55,14 @@ h5 { rgb(19, 104, 145) 50%, rgb(32, 135, 135) 75% ); -} + transition: background-position 0.5s ease-in-out; + background-size: 200% 200%; + background-position: 0% 0%; + color: white; -.btn-sponsor { - background-color: rgb(15, 163, 180); - background-image: linear-gradient( - 140deg, - rgb(0, 128, 154), - rgb(19, 104, 145) 50%, - rgb(32, 135, 135) 75% - ); + &:hover { + background-position: 100% 100%; + } } img { diff --git a/src/Wpf.Ui.Gallery/AssemblyInfo.cs b/src/Wpf.Ui.Gallery/AssemblyInfo.cs index a48496f49..d760c736e 100644 --- a/src/Wpf.Ui.Gallery/AssemblyInfo.cs +++ b/src/Wpf.Ui.Gallery/AssemblyInfo.cs @@ -4,10 +4,6 @@ // All Rights Reserved. [assembly: ThemeInfo( - ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located -//(used if a resource is not found in the page, -// app, or any theme specific resource dictionaries) + ResourceDictionaryLocation.None, + ResourceDictionaryLocation.SourceAssembly )] diff --git a/src/Wpf.Ui.Gallery/Services/ApplicationHostService.cs b/src/Wpf.Ui.Gallery/Services/ApplicationHostService.cs index 59c47a45d..ff8007b58 100644 --- a/src/Wpf.Ui.Gallery/Services/ApplicationHostService.cs +++ b/src/Wpf.Ui.Gallery/Services/ApplicationHostService.cs @@ -4,6 +4,7 @@ // All Rights Reserved. using Wpf.Ui.Gallery.Services.Contracts; +using Wpf.Ui.Gallery.Views.Pages; using Wpf.Ui.Gallery.Views.Windows; namespace Wpf.Ui.Gallery.Services; @@ -25,33 +26,44 @@ public ApplicationHostService(IServiceProvider serviceProvider) /// Triggered when the application host is ready to start the service. /// /// Indicates that the start process has been aborted. - public async Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { - await HandleActivationAsync(); + return HandleActivationAsync(); } /// /// Triggered when the application host is performing a graceful shutdown. /// /// Indicates that the shutdown process should no longer be graceful. - public async Task StopAsync(CancellationToken cancellationToken) + public Task StopAsync(CancellationToken cancellationToken) { - await Task.CompletedTask; + return Task.CompletedTask; } /// /// Creates main window during activation. /// - private async Task HandleActivationAsync() + private Task HandleActivationAsync() { - await Task.CompletedTask; + if (Application.Current.Windows.OfType().Any()) + { + return Task.CompletedTask; + } + + IWindow mainWindow = _serviceProvider.GetRequiredService(); + mainWindow.Loaded += OnMainWindowLoaded; + mainWindow?.Show(); - if (!Application.Current.Windows.OfType().Any()) + return Task.CompletedTask; + } + + private void OnMainWindowLoaded(object sender, RoutedEventArgs e) + { + if (sender is not MainWindow mainWindow) { - var mainWindow = _serviceProvider.GetService(typeof(IWindow)) as IWindow; - mainWindow?.Show(); + return; } - await Task.CompletedTask; + _ = mainWindow.NavigationView.Navigate(typeof(DashboardPage)); } } diff --git a/src/Wpf.Ui.Gallery/Services/Contracts/IWindow.cs b/src/Wpf.Ui.Gallery/Services/Contracts/IWindow.cs index 89f17eef1..9aeb4927e 100644 --- a/src/Wpf.Ui.Gallery/Services/Contracts/IWindow.cs +++ b/src/Wpf.Ui.Gallery/Services/Contracts/IWindow.cs @@ -7,5 +7,7 @@ namespace Wpf.Ui.Gallery.Services.Contracts; public interface IWindow { + event RoutedEventHandler Loaded; + void Show(); } diff --git a/src/Wpf.Ui.Gallery/Usings.cs b/src/Wpf.Ui.Gallery/Usings.cs index e67921be7..6fef748bb 100644 --- a/src/Wpf.Ui.Gallery/Usings.cs +++ b/src/Wpf.Ui.Gallery/Usings.cs @@ -24,4 +24,4 @@ global using System.Windows.Input; global using System.Windows.Markup; global using System.Windows.Media; -global using System.Windows.Threading; \ No newline at end of file +global using System.Windows.Threading; diff --git a/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/DropDownButtonPage.xaml b/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/DropDownButtonPage.xaml index 01353049a..47dfe4242 100644 --- a/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/DropDownButtonPage.xaml +++ b/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/DropDownButtonPage.xaml @@ -25,12 +25,12 @@ XamlCode="<DropDownButton />"> - + - + diff --git a/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/SplitButtonPage.xaml b/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/SplitButtonPage.xaml index a31310d22..6a6391184 100644 --- a/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/SplitButtonPage.xaml +++ b/src/Wpf.Ui.Gallery/Views/Pages/BasicInput/SplitButtonPage.xaml @@ -30,7 +30,7 @@ Background="Green" CornerRadius="4" /> - + - + @@ -74,7 +74,7 @@ Background="Green" CornerRadius="4,0,0,4" /> - + - + diff --git a/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs b/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs index 188b15f0e..c6162052f 100644 --- a/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs +++ b/src/Wpf.Ui.Gallery/Views/Windows/MainWindow.xaml.cs @@ -32,12 +32,12 @@ IContentDialogService contentDialogService contentDialogService.SetContentPresenter(RootContentDialog); NavigationView.SetServiceProvider(serviceProvider); - NavigationView.Loaded += (_, _) => NavigationView.Navigate(typeof(DashboardPage)); } public MainWindowViewModel ViewModel { get; } private bool _isUserClosedPane; + private bool _isPaneOpenedOrClosedFromCode; private void OnNavigationSelectionChanged(object sender, RoutedEventArgs e) diff --git a/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs index 8d44bb42f..764d9aabe 100644 --- a/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs +++ b/src/Wpf.Ui.Gallery/Views/Windows/SandboxWindow.xaml.cs @@ -20,8 +20,13 @@ public SandboxWindow(SandboxWindowViewModel viewModel) InitializeComponent(); } - private void OnAutoSuggestBoxTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) + private void OnAutoSuggestBoxTextChanged( + AutoSuggestBox sender, + AutoSuggestBoxTextChangedEventArgs args + ) { - Debug.WriteLine($"OnAutoSuggestBoxTextChanged: {sender.Text} (ViewModel.AutoSuggestBoxText: {ViewModel.AutoSuggestBoxText})"); + Debug.WriteLine( + $"OnAutoSuggestBoxTextChanged: {sender.Text} (ViewModel.AutoSuggestBoxText: {ViewModel.AutoSuggestBoxText})" + ); } } diff --git a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs index c16971949..0077f00c8 100644 --- a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs +++ b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs @@ -531,7 +531,10 @@ private void UpdateTexBoxTextAfterSelection(object selectedObj) { _changingTextAfterSuggestionChosen = true; - TextBox.SetCurrentValue(System.Windows.Controls.TextBox.TextProperty, GetStringFromObj(selectedObj)); + TextBox.SetCurrentValue( + System.Windows.Controls.TextBox.TextProperty, + GetStringFromObj(selectedObj) + ); _changingTextAfterSuggestionChosen = false; } diff --git a/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.cs b/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.cs index 75d441091..f4ad4bef2 100644 --- a/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.cs +++ b/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.cs @@ -4,8 +4,8 @@ // All Rights Reserved. // ReSharper disable once CheckNamespace -using System.Windows.Controls.Primitives; -using System.Windows.Input; + +using System.Windows.Controls; // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -13,29 +13,9 @@ namespace Wpf.Ui.Controls; /// /// A control that drop downs a flyout of choices from which one can be chosen. /// -[TemplatePart(Name = TemplateElementPopup, Type = typeof(Popup))] -[TemplatePart(Name = TemplateElementToggleButton, Type = typeof(ToggleButton))] public class DropDownButton : Button { - /// - /// Template element represented by the ToggleButton name. - /// - private const string TemplateElementPopup = "Popup"; - - /// - /// Template element represented by the ToggleButton name. - /// - private const string TemplateElementToggleButton = "ToggleButton"; - - /// - /// Control responsible for displaying the flyout elements. - /// - protected Popup DropDownButtonPopup = null!; - - /// - /// Control responsible for toggling the drop-down button. - /// - protected ToggleButton DropDownButtonToggleButton = null!; + private ContextMenu? _contextMenu; /// /// Property for . @@ -54,7 +34,7 @@ public class DropDownButton : Button nameof(IsDropDownOpen), typeof(bool), typeof(DropDownButton), - new PropertyMetadata(false, OnIsDropDownOpenChanged) + new PropertyMetadata(false) ); /// @@ -81,16 +61,6 @@ public bool IsDropDownOpen set => SetValue(IsDropDownOpenProperty, value); } - public DropDownButton() - { - Unloaded += static (sender, _) => - { - var self = (DropDownButton)sender; - - self.ReleaseTemplateResources(); - }; - } - private static void OnFlyoutChangedCallback( DependencyObject d, DependencyPropertyChangedEventArgs e @@ -102,114 +72,43 @@ DependencyPropertyChangedEventArgs e } } - protected virtual void OnFlyoutChangedCallback(object value) { } - - private static void OnIsDropDownOpenChanged( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) + protected virtual void OnFlyoutChangedCallback(object value) { - if (d is DropDownButton dropDownButton) + if (value is ContextMenu contextMenu) { - dropDownButton.OnIsDropDownOpenChanged(e.NewValue is bool ? (bool)e.NewValue : false); + _contextMenu = contextMenu; + _contextMenu.Opened += OnContextMenuOpened; + _contextMenu.Closed += OnContextMenuClosed; } } - protected virtual void OnIsDropDownOpenChanged(bool currentValue) { } - - protected override void OnClick() + protected virtual void OnContextMenuClosed(object sender, RoutedEventArgs e) { - base.OnClick(); - - SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen); - - if (DropDownButtonToggleButton is not null) - { - DropDownButtonToggleButton.SetCurrentValue( - ToggleButton.IsCheckedProperty, - IsDropDownOpen - ); - } + SetCurrentValue(IsDropDownOpenProperty, false); } - /// - public override void OnApplyTemplate() + protected virtual void OnContextMenuOpened(object sender, RoutedEventArgs e) { - base.OnApplyTemplate(); - - if (GetTemplateChild(TemplateElementPopup) is Popup popup) - { - DropDownButtonPopup = popup; - } - else - { - throw new NullReferenceException( - $"Element {nameof(TemplateElementPopup)} of type {typeof(Popup)} not found in {typeof(DropDownButton)}" - ); - } - - if (GetTemplateChild(TemplateElementToggleButton) is ToggleButton toggleButton) - { - DropDownButtonToggleButton = toggleButton; - - DropDownButtonToggleButton.Click -= OnDropDownButtonToggleButtonOnClick; - DropDownButtonToggleButton.Click += OnDropDownButtonToggleButtonOnClick; - } - else - { - throw new NullReferenceException( - $"Element {nameof(TemplateElementToggleButton)} of type {typeof(ToggleButton)} not found in {typeof(DropDownButton)}" - ); - } + SetCurrentValue(IsDropDownOpenProperty, true); } - /// - /// Triggered when the control is unloaded. Releases resource bindings. - /// - protected virtual void ReleaseTemplateResources() - { - DropDownButtonToggleButton.Click -= OnDropDownButtonToggleButtonOnClick; - } - - /// - protected override void OnLostFocus(RoutedEventArgs e) - { - base.OnLostFocus(e); - - if (IsDropDownOpen) - { - SetCurrentValue(IsDropDownOpenProperty, false); - } - } + protected virtual void OnIsDropDownOpenChanged(bool currentValue) { } - /// - protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e) + protected override void OnClick() { - base.OnLostKeyboardFocus(e); - - if (IsDropDownOpen) - { - SetCurrentValue(IsDropDownOpenProperty, false); - } - } + base.OnClick(); - private void OnDropDownButtonToggleButtonOnClick(object sender, RoutedEventArgs e) - { - if (sender is not ToggleButton toggleButton) + if (_contextMenu is null) { return; } - SetCurrentValue(IsDropDownOpenProperty, toggleButton.IsChecked); - } - - protected T GetTemplateChild(string name) where T : DependencyObject - { - if (GetTemplateChild(name) is not T dependencyObject) - { - throw new ArgumentNullException(name); - } - - return dependencyObject; + _contextMenu.SetCurrentValue(MinWidthProperty, ActualWidth); + _contextMenu.SetCurrentValue(ContextMenu.PlacementTargetProperty, this); + _contextMenu.SetCurrentValue( + ContextMenu.PlacementProperty, + System.Windows.Controls.Primitives.PlacementMode.Bottom + ); + _contextMenu.SetCurrentValue(ContextMenu.IsOpenProperty, true); } } diff --git a/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.xaml b/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.xaml index c3136bf0d..45bd8e73e 100644 --- a/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.xaml +++ b/src/Wpf.Ui/Controls/DropDownButton/DropDownButton.xaml @@ -18,164 +18,63 @@ - - 8,0,0,0 - - + + - + +