From 34038510ac7e5c801125fa2515b21b11c60af814 Mon Sep 17 00:00:00 2001 From: Kevin Bost Date: Sun, 2 Oct 2022 21:41:08 -0700 Subject: [PATCH 1/4] Adding the ability for the dialog title to contain arbitrary content Fixes #4350 --- .../Peers/MetroDialogAutomationPeer.cs | 6 +-- .../Controls/Dialogs/BaseMetroDialog.cs | 8 ++-- .../Controls/Dialogs/DialogManager.cs | 8 ++-- .../Dialogs/ProgressDialogController.cs | 2 +- .../Themes/Dialogs/BaseMetroDialog.xaml | 19 +++++--- .../MahApps.Metro.Tests.csproj | 12 +++++ .../Tests/CustomDialogTest.cs | 46 ++++++++++++++++++- .../Views/DialogCustomTitleWindow.xaml | 23 ++++++++++ .../Views/DialogCustomTitleWindow.xaml.cs | 16 +++++++ .../Views/DialogWindow.xaml | 2 +- 10 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml create mode 100644 src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml.cs diff --git a/src/MahApps.Metro/Automation/Peers/MetroDialogAutomationPeer.cs b/src/MahApps.Metro/Automation/Peers/MetroDialogAutomationPeer.cs index 764d5ff039..069fb132b6 100644 --- a/src/MahApps.Metro/Automation/Peers/MetroDialogAutomationPeer.cs +++ b/src/MahApps.Metro/Automation/Peers/MetroDialogAutomationPeer.cs @@ -27,11 +27,11 @@ protected override AutomationControlType GetAutomationControlTypeCore() protected override string GetNameCore() { var nameCore = base.GetNameCore(); - if (string.IsNullOrEmpty(nameCore)) + if (string.IsNullOrEmpty(nameCore) && ((BaseMetroDialog)this.Owner).Title is string title) { - nameCore = ((BaseMetroDialog)this.Owner).Title; + nameCore = title; } - + if (string.IsNullOrEmpty(nameCore)) { nameCore = ((BaseMetroDialog)this.Owner).Name; diff --git a/src/MahApps.Metro/Controls/Dialogs/BaseMetroDialog.cs b/src/MahApps.Metro/Controls/Dialogs/BaseMetroDialog.cs index 8fc30970d8..1d8bac64a8 100644 --- a/src/MahApps.Metro/Controls/Dialogs/BaseMetroDialog.cs +++ b/src/MahApps.Metro/Controls/Dialogs/BaseMetroDialog.cs @@ -83,16 +83,16 @@ public GridLength DialogContentWidth /// Identifies the dependency property. public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), - typeof(string), + typeof(object), typeof(BaseMetroDialog), - new PropertyMetadata(default(string))); + new PropertyMetadata(default(object))); /// /// Gets or sets the title of the dialog. /// - public string? Title + public object? Title { - get => (string?)this.GetValue(TitleProperty); + get => (object?)this.GetValue(TitleProperty); set => this.SetValue(TitleProperty, value); } diff --git a/src/MahApps.Metro/Controls/Dialogs/DialogManager.cs b/src/MahApps.Metro/Controls/Dialogs/DialogManager.cs index 8b4e477a99..b1fb2a1287 100644 --- a/src/MahApps.Metro/Controls/Dialogs/DialogManager.cs +++ b/src/MahApps.Metro/Controls/Dialogs/DialogManager.cs @@ -24,7 +24,7 @@ public static class DialogManager /// The message contained within the LoginDialog. /// Optional settings that override the global metro dialog settings. /// The text that was entered or null (Nothing in Visual Basic) if the user cancelled the operation. - public static async Task ShowLoginAsync(this MetroWindow window, string title, string message, LoginDialogSettings? settings = null) + public static async Task ShowLoginAsync(this MetroWindow window, object title, string message, LoginDialogSettings? settings = null) { window.Dispatcher.VerifyAccess(); @@ -73,7 +73,7 @@ public static class DialogManager /// The message contained within the MessageDialog. /// Optional settings that override the global metro dialog settings. /// The text that was entered or null (Nothing in Visual Basic) if the user cancelled the operation. - public static async Task ShowInputAsync(this MetroWindow window, string title, string message, MetroDialogSettings? settings = null) + public static async Task ShowInputAsync(this MetroWindow window, object title, string message, MetroDialogSettings? settings = null) { window.Dispatcher.VerifyAccess(); @@ -124,7 +124,7 @@ public static class DialogManager /// The type of buttons to use. /// Optional settings that override the global metro dialog settings. /// A task promising the result of which button was pressed. - public static async Task ShowMessageAsync(this MetroWindow window, string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, MetroDialogSettings? settings = null) + public static async Task ShowMessageAsync(this MetroWindow window, object title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, MetroDialogSettings? settings = null) { window.Dispatcher.VerifyAccess(); @@ -175,7 +175,7 @@ public static async Task ShowMessageAsync(this MetroWindow /// Determines if the cancel button is visible. /// Optional Settings that override the global metro dialog settings. /// A task promising the instance of ProgressDialogController for this operation. - public static async Task ShowProgressAsync(this MetroWindow window, string title, string message, bool isCancelable = false, MetroDialogSettings? settings = null) + public static async Task ShowProgressAsync(this MetroWindow window, object title, string message, bool isCancelable = false, MetroDialogSettings? settings = null) { window.Dispatcher.VerifyAccess(); diff --git a/src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs b/src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs index 59c54d6eb5..7635780cd8 100644 --- a/src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs +++ b/src/MahApps.Metro/Controls/Dialogs/ProgressDialogController.cs @@ -147,7 +147,7 @@ public void SetMessage(string message) /// Sets the dialog's title. /// /// The title to be set. - public void SetTitle(string title) + public void SetTitle(object title) { this.WrappedDialog.Invoke(() => this.WrappedDialog.Title = title); } diff --git a/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml b/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml index ff67650b4e..ee4dd0da72 100644 --- a/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml +++ b/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml @@ -79,13 +79,18 @@ - + + + + + + + + + DialogCustomTitleWindow.xaml + + + + + + $(DefaultXamlRuntime) + + \ No newline at end of file diff --git a/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs b/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs index dd14da0895..584f3bafaf 100644 --- a/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs +++ b/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs @@ -2,7 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Drawing; +using System.Linq; using System.Threading.Tasks; +using System.Windows; using System.Windows.Controls; using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; @@ -33,10 +36,48 @@ public async Task ReceivesDataContext() Assert.Null(await window.GetCurrentDialogAsync()); dialog.DataContext = vm; - var textBlock = dialog.FindChild("TheDialogBody"); + var bodyTextBlock = dialog.FindChild("TheDialogBody"); - Assert.Equal(vm.Text, textBlock.Text); + Assert.Equal(vm.Text, bodyTextBlock.Text); + var title = dialog.FindChild("PART_Title"); + + Assert.Equal(vm.Title, title.Content); + + await window.HideMetroDialogAsync(dialog); + + await TestHost.SwitchToAppThread(); // No idea why we have to do this again + + Assert.Null(await window.GetCurrentDialogAsync()); + } + + [Fact] + [DisplayTestMethodName] + public async Task DisplaysTitleWithCustomContent() + { + await TestHost.SwitchToAppThread(); + + var window = await WindowHelpers.CreateInvisibleWindowAsync(); + var vm = new TheViewModel(); + var dialog = (CustomDialog)window.Resources["CustomDialog"]; + + await window.ShowMetroDialogAsync(dialog); + + await TestHost.SwitchToAppThread(); // No idea why we have to do this again + + Assert.Equal(await window.GetCurrentDialogAsync(), dialog); + Assert.NotNull(await window.GetCurrentDialogAsync()); + Assert.Null(await window.GetCurrentDialogAsync()); + + dialog.DataContext = vm; + + var titleContainer = dialog.FindChild("TheDialogTitle"); + + var rects = titleContainer.FindChildren().ToList(); + Assert.Equal(2, rects.Count); + TextBlock text = titleContainer.FindChild(); + Assert.Equal(vm.Title, text.Text); + await window.HideMetroDialogAsync(dialog); await TestHost.SwitchToAppThread(); // No idea why we have to do this again @@ -47,6 +88,7 @@ public async Task ReceivesDataContext() private class TheViewModel { public string Text => "TheText"; + public string Title => "TheTitle"; } } } \ No newline at end of file diff --git a/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml b/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml new file mode 100644 index 0000000000..8339a29500 --- /dev/null +++ b/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml.cs b/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml.cs new file mode 100644 index 0000000000..eec2c57828 --- /dev/null +++ b/src/Mahapps.Metro.Tests/Views/DialogCustomTitleWindow.xaml.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using MahApps.Metro.Controls; + +namespace MahApps.Metro.Tests.Views +{ + public partial class DialogCustomTitleWindow : MetroWindow + { + public DialogCustomTitleWindow() + { + this.InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/src/Mahapps.Metro.Tests/Views/DialogWindow.xaml b/src/Mahapps.Metro.Tests/Views/DialogWindow.xaml index 7334b32b74..711c37b4e8 100644 --- a/src/Mahapps.Metro.Tests/Views/DialogWindow.xaml +++ b/src/Mahapps.Metro.Tests/Views/DialogWindow.xaml @@ -8,7 +8,7 @@ d:DesignWidth="300" mc:Ignorable="d"> - + From 169713cc5c27fb57807ac79055f82236e84011c4 Mon Sep 17 00:00:00 2001 From: punker76 Date: Sat, 8 Oct 2022 21:33:42 +0200 Subject: [PATCH 2/4] refactor: #4350 additional items in project file not needed --- src/Mahapps.Metro.Tests/MahApps.Metro.Tests.csproj | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Mahapps.Metro.Tests/MahApps.Metro.Tests.csproj b/src/Mahapps.Metro.Tests/MahApps.Metro.Tests.csproj index 225c355359..886436058c 100644 --- a/src/Mahapps.Metro.Tests/MahApps.Metro.Tests.csproj +++ b/src/Mahapps.Metro.Tests/MahApps.Metro.Tests.csproj @@ -40,16 +40,4 @@ - - - - DialogCustomTitleWindow.xaml - - - - - - $(DefaultXamlRuntime) - - \ No newline at end of file From 8499c7d9f29e63c18475d4e5f6cd167e1119b2ab Mon Sep 17 00:00:00 2001 From: punker76 Date: Sat, 8 Oct 2022 21:34:26 +0200 Subject: [PATCH 3/4] refactor: #4350 switching twice to app thread not needed --- src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs b/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs index 584f3bafaf..6c5eada4f9 100644 --- a/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs +++ b/src/Mahapps.Metro.Tests/Tests/CustomDialogTest.cs @@ -2,10 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Drawing; using System.Linq; using System.Threading.Tasks; -using System.Windows; using System.Windows.Controls; using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; @@ -29,8 +27,6 @@ public async Task ReceivesDataContext() await window.ShowMetroDialogAsync(dialog); - await TestHost.SwitchToAppThread(); // No idea why we have to do this again - Assert.Equal(await window.GetCurrentDialogAsync(), dialog); Assert.NotNull(await window.GetCurrentDialogAsync()); Assert.Null(await window.GetCurrentDialogAsync()); @@ -46,8 +42,6 @@ public async Task ReceivesDataContext() await window.HideMetroDialogAsync(dialog); - await TestHost.SwitchToAppThread(); // No idea why we have to do this again - Assert.Null(await window.GetCurrentDialogAsync()); } @@ -63,8 +57,6 @@ public async Task DisplaysTitleWithCustomContent() await window.ShowMetroDialogAsync(dialog); - await TestHost.SwitchToAppThread(); // No idea why we have to do this again - Assert.Equal(await window.GetCurrentDialogAsync(), dialog); Assert.NotNull(await window.GetCurrentDialogAsync()); Assert.Null(await window.GetCurrentDialogAsync()); @@ -80,8 +72,6 @@ public async Task DisplaysTitleWithCustomContent() await window.HideMetroDialogAsync(dialog); - await TestHost.SwitchToAppThread(); // No idea why we have to do this again - Assert.Null(await window.GetCurrentDialogAsync()); } From 06385f1cd7533a1b139b92755a12539ed23edcba Mon Sep 17 00:00:00 2001 From: punker76 Date: Sat, 8 Oct 2022 21:35:05 +0200 Subject: [PATCH 4/4] refactor: xaml styler --- .../MahApps.Metro.Demo/MainWindow.xaml | 6 ++-- .../Styles/Controls.Buttons.xaml | 4 +-- .../Themes/Dialogs/BaseMetroDialog.xaml | 6 ++-- src/MahApps.Metro/Themes/MetroWindow.xaml | 14 +++++----- .../Themes/WindowButtonCommands.xaml | 28 +++++++++---------- .../Views/DialogCustomTitleWindow.xaml | 12 ++++++-- 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MainWindow.xaml b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MainWindow.xaml index 84a25b077a..ba692b2041 100644 --- a/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MainWindow.xaml +++ b/src/MahApps.Metro.Samples/MahApps.Metro.Demo/MainWindow.xaml @@ -1,13 +1,13 @@  + IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mah:MetroWindow}}, Path=DWMSupportsBorderColor}" + IsEnabled="False" /> + xmlns:mahConverters="clr-namespace:MahApps.Metro.Converters"> diff --git a/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml b/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml index ee4dd0da72..da3f4502f0 100644 --- a/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml +++ b/src/MahApps.Metro/Themes/Dialogs/BaseMetroDialog.xaml @@ -82,11 +82,11 @@ + TextElement.Foreground="{TemplateBinding Foreground}"> - diff --git a/src/MahApps.Metro/Themes/MetroWindow.xaml b/src/MahApps.Metro/Themes/MetroWindow.xaml index 1d78eca351..4a624c1f5a 100644 --- a/src/MahApps.Metro/Themes/MetroWindow.xaml +++ b/src/MahApps.Metro/Themes/MetroWindow.xaml @@ -1,4 +1,4 @@ - @@ -204,10 +204,10 @@ + Visibility="Collapsed" /> @@ -299,9 +299,9 @@ HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Panel.ZIndex="1" + controlzEx:WindowChrome.IsHitTestVisibleInChrome="True" Content="{TemplateBinding Icon}" ContentTemplate="{TemplateBinding IconTemplate}" - controlzEx:WindowChrome.IsHitTestVisibleInChrome="True" Focusable="False" Visibility="{TemplateBinding ShowIconOnTitleBar, Converter={StaticResource BooleanToVisibilityConverter}}" /> @@ -456,10 +456,10 @@ + Visibility="Collapsed" /> diff --git a/src/MahApps.Metro/Themes/WindowButtonCommands.xaml b/src/MahApps.Metro/Themes/WindowButtonCommands.xaml index 28d075588d..f740a07d96 100644 --- a/src/MahApps.Metro/Themes/WindowButtonCommands.xaml +++ b/src/MahApps.Metro/Themes/WindowButtonCommands.xaml @@ -1,18 +1,18 @@  + xmlns:mahConverters="clr-namespace:MahApps.Metro.Converters">