From 2fc894035733f92654dbce62d3b3e6570a54f4ae Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sat, 10 Dec 2022 15:23:43 +0100 Subject: [PATCH 01/14] Limit solution to "AnyCPU" only --- .../CustomMessageBox Demo.csproj | 19 ------------------- source/WPFCustomMessageBox.sln | 19 +++++++------------ .../WPFCustomMessageBox.csproj | 19 ------------------- 3 files changed, 7 insertions(+), 50 deletions(-) diff --git a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj index ff5c399..1d5fbf9 100644 --- a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj +++ b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj @@ -16,25 +16,6 @@ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AnyCPU bin\Debug\ diff --git a/source/WPFCustomMessageBox.sln b/source/WPFCustomMessageBox.sln index a7770f7..564d1bd 100644 --- a/source/WPFCustomMessageBox.sln +++ b/source/WPFCustomMessageBox.sln @@ -1,6 +1,8 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32802.440 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFCustomMessageBox", "WPFCustomMessageBox\WPFCustomMessageBox.csproj", "{ED02D418-7C0E-4E6C-99A9-BE4357122AE7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomMessageBox Demo", "CustomMessageBoxDemo\CustomMessageBox Demo.csproj", "{BEB8F894-9C79-4D30-8061-C5570C1B159D}" @@ -8,29 +10,22 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Debug|x86.ActiveCfg = Debug|x86 - {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Debug|x86.Build.0 = Debug|x86 {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Release|Any CPU.Build.0 = Release|Any CPU - {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Release|x86.ActiveCfg = Release|x86 - {ED02D418-7C0E-4E6C-99A9-BE4357122AE7}.Release|x86.Build.0 = Release|x86 {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Debug|x86.ActiveCfg = Debug|x86 - {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Debug|x86.Build.0 = Debug|x86 {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Release|Any CPU.ActiveCfg = Release|Any CPU {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Release|Any CPU.Build.0 = Release|Any CPU - {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Release|x86.ActiveCfg = Release|x86 - {BEB8F894-9C79-4D30-8061-C5570C1B159D}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9BCF4E1F-DFC2-4BCC-9C10-AF9F64AED105} + EndGlobalSection EndGlobal diff --git a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj index 08c328d..83a6617 100644 --- a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj +++ b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj @@ -16,25 +16,6 @@ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - From a6e262f92c8023b9483425d44c8d8f8b759faf05 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sat, 10 Dec 2022 15:39:26 +0100 Subject: [PATCH 02/14] remove unnecessary namespaces --- .../CustomMessageBoxWindow.xaml.cs | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs index 11badd4..de745dd 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs @@ -110,42 +110,42 @@ private void DisplayButtons(MessageBoxButton button) { case MessageBoxButton.OKCancel: // Hide all but OK, Cancel - this.Button_OK.Visibility = System.Windows.Visibility.Visible; + this.Button_OK.Visibility = Visibility.Visible; this.Button_OK.Focus(); - this.Button_Cancel.Visibility = System.Windows.Visibility.Visible; + this.Button_Cancel.Visibility = Visibility.Visible; - this.Button_Yes.Visibility = System.Windows.Visibility.Collapsed; - this.Button_No.Visibility = System.Windows.Visibility.Collapsed; + this.Button_Yes.Visibility = Visibility.Collapsed; + this.Button_No.Visibility = Visibility.Collapsed; break; case MessageBoxButton.YesNo: // Hide all but Yes, No - this.Button_Yes.Visibility = System.Windows.Visibility.Visible; + this.Button_Yes.Visibility = Visibility.Visible; this.Button_Yes.Focus(); - this.Button_No.Visibility = System.Windows.Visibility.Visible; + this.Button_No.Visibility = Visibility.Visible; - this.Button_OK.Visibility = System.Windows.Visibility.Collapsed; - this.Button_Cancel.Visibility = System.Windows.Visibility.Collapsed; + this.Button_OK.Visibility = Visibility.Collapsed; + this.Button_Cancel.Visibility = Visibility.Collapsed; break; case MessageBoxButton.YesNoCancel: // Hide only OK - this.Button_Yes.Visibility = System.Windows.Visibility.Visible; + this.Button_Yes.Visibility = Visibility.Visible; this.Button_Yes.Focus(); - this.Button_No.Visibility = System.Windows.Visibility.Visible; - this.Button_Cancel.Visibility = System.Windows.Visibility.Visible; + this.Button_No.Visibility = Visibility.Visible; + this.Button_Cancel.Visibility = Visibility.Visible; - this.Button_OK.Visibility = System.Windows.Visibility.Collapsed; + this.Button_OK.Visibility = Visibility.Collapsed; break; default: // Hide all but OK - this.Button_OK.Visibility = System.Windows.Visibility.Visible; + this.Button_OK.Visibility = Visibility.Visible; this.Button_OK.Focus(); - this.Button_Yes.Visibility = System.Windows.Visibility.Collapsed; - this.Button_No.Visibility = System.Windows.Visibility.Collapsed; - this.Button_Cancel.Visibility = System.Windows.Visibility.Collapsed; + this.Button_Yes.Visibility = Visibility.Collapsed; + this.Button_No.Visibility = Visibility.Collapsed; + this.Button_Cancel.Visibility = Visibility.Collapsed; break; } } From 5e7f7329959d7abe5957ed4c23f171864a9d5977 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sat, 10 Dec 2022 16:03:20 +0100 Subject: [PATCH 03/14] Allow the user to provide own 32x32 pixel images --- .../WPFCustomMessageBox/CustomMessageBox.cs | 121 ++++++++++++++++++ .../CustomMessageBoxWindow.xaml.cs | 45 ++----- source/WPFCustomMessageBox/MessageBoxData.cs | 24 +++- 3 files changed, 151 insertions(+), 39 deletions(-) diff --git a/source/WPFCustomMessageBox/CustomMessageBox.cs b/source/WPFCustomMessageBox/CustomMessageBox.cs index aba00e9..43a3ed1 100644 --- a/source/WPFCustomMessageBox/CustomMessageBox.cs +++ b/source/WPFCustomMessageBox/CustomMessageBox.cs @@ -7,6 +7,7 @@ namespace WPFCustomMessageBox { using System.Windows; + using System.Windows.Media; /// /// Displays a message box. @@ -121,6 +122,27 @@ public static MessageBoxResult Show(string messageBoxText, string caption, Messa return msgData.ShowMessageBox(); } + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A System.String that specifies the text to display. + /// A System.String that specifies the title bar caption to display. + /// A System.Windows.MessageBoxButton value that specifies which button or buttons to display. + /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. + /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, ImageSource icon) + { + var msgData = new MessageBoxData() + { + Message = messageBoxText, + Caption = caption, + Buttons = button, + Icon = icon + }; + + return msgData.ShowMessageBox(); + } + /// /// Displays a message box that has a message, title bar caption, and OK button with a custom System.String value for the button's text; and that returns a result. /// @@ -163,6 +185,28 @@ public static MessageBoxResult ShowOK(string messageBoxText, string caption, str return msgData.ShowMessageBox(); } + /// + /// Displays a message box that has a message, title bar caption, OK button with a custom System.String value for the button's text, and icon; and that returns a result. + /// + /// A System.String that specifies the text to display. + /// A System.String that specifies the title bar caption to display. + /// A System.String that specifies the text to display within the OK button. + /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. + /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. + public static MessageBoxResult ShowOK(string messageBoxText, string caption, string okButtonText, ImageSource icon) + { + var msgData = new MessageBoxData() + { + Message = messageBoxText, + Caption = caption, + Buttons = MessageBoxButton.OK, + Icon = icon, + OkButtonCaption = okButtonText + }; + + return msgData.ShowMessageBox(); + } + /// /// Displays a message box that has a message, caption, and OK/Cancel buttons with custom System.String values for the buttons' text; /// and that returns a result. @@ -211,6 +255,31 @@ public static MessageBoxResult ShowOKCancel(string messageBoxText, string captio return msgData.ShowMessageBox(); } + /// + /// Displays a message box that has a message, caption, OK/Cancel buttons with custom System.String values for the buttons' text, and icon; + /// and that returns a result. + /// + /// A System.String that specifies the text to display. + /// A System.String that specifies the title bar caption to display. + /// A System.String that specifies the text to display within the OK button. + /// A System.String that specifies the text to display within the Cancel button. + /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. + /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. + public static MessageBoxResult ShowOKCancel(string messageBoxText, string caption, string okButtonText, string cancelButtonText, ImageSource icon) + { + var msgData = new MessageBoxData() + { + Message = messageBoxText, + Caption = caption, + Buttons = MessageBoxButton.OKCancel, + Icon = icon, + OkButtonCaption = okButtonText, + CancelButtonCaption = cancelButtonText + }; + + return msgData.ShowMessageBox(); + } + /// /// Displays a message box that has a message, caption, and Yes/No buttons with custom System.String values for the buttons' text; /// and that returns a result. @@ -259,6 +328,31 @@ public static MessageBoxResult ShowYesNo(string messageBoxText, string caption, return msgData.ShowMessageBox(); } + /// + /// Displays a message box that has a message, caption, Yes/No buttons with custom System.String values for the buttons' text, and icon; + /// and that returns a result. + /// + /// A System.String that specifies the text to display. + /// A System.String that specifies the title bar caption to display. + /// A System.String that specifies the text to display within the Yes button. + /// A System.String that specifies the text to display within the No button. + /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. + /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. + public static MessageBoxResult ShowYesNo(string messageBoxText, string caption, string yesButtonText, string noButtonText, ImageSource icon) + { + var msgData = new MessageBoxData() + { + Message = messageBoxText, + Caption = caption, + Buttons = MessageBoxButton.YesNo, + Icon = icon, + YesButtonCaption = yesButtonText, + NoButtonCaption = noButtonText + }; + + return msgData.ShowMessageBox(); + } + /// /// Displays a message box that has a message, caption, and Yes/No/Cancel buttons with custom System.String values for the buttons' text; /// and that returns a result. @@ -310,5 +404,32 @@ public static MessageBoxResult ShowYesNoCancel(string messageBoxText, string cap return msgData.ShowMessageBox(); } + + /// + /// Displays a message box that has a message, caption, Yes/No/Cancel buttons with custom System.String values for the buttons' text, and icon; + /// and that returns a result. + /// + /// A System.String that specifies the text to display. + /// A System.String that specifies the title bar caption to display. + /// A System.String that specifies the text to display within the Yes button. + /// A System.String that specifies the text to display within the No button. + /// A System.String that specifies the text to display within the Cancel button. + /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. + /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. + public static MessageBoxResult ShowYesNoCancel(string messageBoxText, string caption, string yesButtonText, string noButtonText, string cancelButtonText, ImageSource icon) + { + var msgData = new MessageBoxData() + { + Message = messageBoxText, + Caption = caption, + Buttons = MessageBoxButton.YesNoCancel, + Icon = icon, + YesButtonCaption = yesButtonText, + NoButtonCaption = noButtonText, + CancelButtonCaption = cancelButtonText + }; + + return msgData.ShowMessageBox(); + } } } diff --git a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs index de745dd..1ca453b 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.Windows; +using System.Windows.Media; namespace WPFCustomMessageBox { @@ -88,15 +89,19 @@ internal string NoButtonText #region Constructor - internal CustomMessageBoxWindow(string message, string caption, MessageBoxButton button, MessageBoxImage image) + internal CustomMessageBoxWindow(string message, string caption, MessageBoxButton button, ImageSource icon) { this.InitializeComponent(); this.Message = message; this.Caption = caption; - this.Image_MessageBox.Visibility = Visibility.Collapsed; - this.DisplayImage(image); + if (icon != null) // Display image/icon + { + this.Image_MessageBox.Source = icon; + this.Image_MessageBox.Visibility = Visibility.Visible; + } + this.DisplayButtons(button); } @@ -150,40 +155,6 @@ private void DisplayButtons(MessageBoxButton button) } } - private void DisplayImage(MessageBoxImage image) - { - Icon icon; - - switch (image) - { - case MessageBoxImage.None: - return; - - case MessageBoxImage.Exclamation: // Enumeration value 48 - also covers "Warning" - icon = SystemIcons.Exclamation; - break; - - case MessageBoxImage.Error: // Enumeration value 16, also covers "Hand" and "Stop" - icon = SystemIcons.Hand; - break; - - case MessageBoxImage.Information: // Enumeration value 64 - also covers "Asterisk" - icon = SystemIcons.Information; - break; - - case MessageBoxImage.Question: - icon = SystemIcons.Question; - break; - - default: - icon = SystemIcons.Information; - break; - } - - this.Image_MessageBox.Source = icon.ToImageSource(); - this.Image_MessageBox.Visibility = Visibility.Visible; - } - private void Button_OK_Click(object sender, RoutedEventArgs e) { this.Result = MessageBoxResult.OK; diff --git a/source/WPFCustomMessageBox/MessageBoxData.cs b/source/WPFCustomMessageBox/MessageBoxData.cs index f3e992e..a3ed4d4 100644 --- a/source/WPFCustomMessageBox/MessageBoxData.cs +++ b/source/WPFCustomMessageBox/MessageBoxData.cs @@ -1,5 +1,8 @@ -using System.Threading; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; using System.Windows; +using System.Windows.Media; namespace WPFCustomMessageBox { @@ -17,6 +20,8 @@ internal class MessageBoxData public MessageBoxImage Image { get; set; } = MessageBoxImage.None; + public ImageSource Icon { get; set; } + public string YesButtonCaption { get; set; } public string NoButtonCaption { get; set; } @@ -27,6 +32,19 @@ internal class MessageBoxData public MessageBoxResult Result { get; set; } = MessageBoxResult.None; + private static Dictionary IconLookup { get; } = new Dictionary() + { + { MessageBoxImage.None, null }, + { MessageBoxImage.Hand, SystemIcons.Hand }, + { MessageBoxImage.Stop, SystemIcons.Hand }, + { MessageBoxImage.Error, SystemIcons.Hand }, + { MessageBoxImage.Question, SystemIcons.Question }, + { MessageBoxImage.Exclamation, SystemIcons.Exclamation }, + { MessageBoxImage.Warning, SystemIcons.Warning }, + { MessageBoxImage.Asterisk, SystemIcons.Information }, + { MessageBoxImage.Information, SystemIcons.Information } + }; + #endregion #region Methods @@ -56,7 +74,9 @@ public MessageBoxResult ShowMessageBox() private void ShowMessageBoxSTA() { - var msg = new CustomMessageBoxWindow(this.Message, this.Caption, this.Buttons, this.Image); + this.Icon = this.Icon ?? MessageBoxData.IconLookup[this.Image].ToImageSource(); + + var msg = new CustomMessageBoxWindow(this.Message, this.Caption, this.Buttons, this.Icon); msg.YesButtonText = this.YesButtonCaption ?? msg.YesButtonText; msg.NoButtonText = this.NoButtonCaption ?? msg.NoButtonText; From 592a1a638d865d4d40fa5e1df0efe19693b29efe Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sat, 10 Dec 2022 16:14:36 +0100 Subject: [PATCH 04/14] Fix bug and add example in demo GUI --- .../CustomMessageBox Demo.csproj | 1 + source/CustomMessageBoxDemo/MainWindow.xaml | 5 +++-- source/CustomMessageBoxDemo/MainWindow.xaml.cs | 13 +++++++++++++ source/WPFCustomMessageBox/MessageBoxData.cs | 10 +++------- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj index 1d5fbf9..f1b6324 100644 --- a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj +++ b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj @@ -27,6 +27,7 @@ + diff --git a/source/CustomMessageBoxDemo/MainWindow.xaml b/source/CustomMessageBoxDemo/MainWindow.xaml index 6e87820..3c40abb 100644 --- a/source/CustomMessageBoxDemo/MainWindow.xaml +++ b/source/CustomMessageBoxDemo/MainWindow.xaml @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowStartupLocation="CenterScreen" - Title="MainWindow" Height="296" Width="550" Loaded="Window_Loaded"> + Title="MainWindow" Height="296" Width="570" Loaded="Window_Loaded"> + + + + + + + + + + + + + + diff --git a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs new file mode 100644 index 0000000..673f196 --- /dev/null +++ b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs @@ -0,0 +1,33 @@ +using System.Windows; +using System.Windows.Controls; + +namespace WPFCustomMessageBox +{ + /// + /// Interaction logic for ModalDialog.xaml + /// + internal partial class CustomMessageBoxView : Window + { + internal CustomMessageBoxView() + { + this.InitializeComponent(); + } + + internal void ButtonClick(object sender, RoutedEventArgs e) + { + switch ((e.Source as Button)?.Name) + { + case "FirstButton": + break; + case "SecondButton": + break; + case "ThirdButton": + break; + default: + break; + } + + this.Close(); + } + } +} diff --git a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml deleted file mode 100644 index 871cfbc..0000000 --- a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs b/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs deleted file mode 100644 index 1ca453b..0000000 --- a/source/WPFCustomMessageBox/CustomMessageBoxWindow.xaml.cs +++ /dev/null @@ -1,184 +0,0 @@ -using System.Drawing; -using System.Windows; -using System.Windows.Media; - -namespace WPFCustomMessageBox -{ - /// - /// Interaction logic for ModalDialog.xaml - /// - internal partial class CustomMessageBoxWindow : Window - { - #region Properties - - internal string Caption - { - get - { - return this.Title; - } - set - { - this.Title = value; - } - } - - internal string Message - { - get - { - return this.TextBlock_Message.Text; - } - set - { - this.TextBlock_Message.Text = value; - } - } - - internal string OkButtonText - { - get - { - return this.Label_Ok.Content.ToString(); - } - set - { - this.Label_Ok.Content = value.TryAddKeyboardAccellerator(); - } - } - - internal string CancelButtonText - { - get - { - return this.Label_Cancel.Content.ToString(); - } - set - { - this.Label_Cancel.Content = value.TryAddKeyboardAccellerator(); - } - } - - internal string YesButtonText - { - get - { - return this.Label_Yes.Content.ToString(); - } - set - { - this.Label_Yes.Content = value.TryAddKeyboardAccellerator(); - } - } - - internal string NoButtonText - { - get - { - return this.Label_No.Content.ToString(); - } - set - { - this.Label_No.Content = value.TryAddKeyboardAccellerator(); - } - } - - public MessageBoxResult Result { get; set; } - - #endregion - - #region Constructor - - internal CustomMessageBoxWindow(string message, string caption, MessageBoxButton button, ImageSource icon) - { - this.InitializeComponent(); - - this.Message = message; - this.Caption = caption; - - if (icon != null) // Display image/icon - { - this.Image_MessageBox.Source = icon; - this.Image_MessageBox.Visibility = Visibility.Visible; - } - - this.DisplayButtons(button); - } - - #endregion - - #region Methods - - private void DisplayButtons(MessageBoxButton button) - { - switch (button) - { - case MessageBoxButton.OKCancel: - // Hide all but OK, Cancel - this.Button_OK.Visibility = Visibility.Visible; - this.Button_OK.Focus(); - this.Button_Cancel.Visibility = Visibility.Visible; - - this.Button_Yes.Visibility = Visibility.Collapsed; - this.Button_No.Visibility = Visibility.Collapsed; - break; - - case MessageBoxButton.YesNo: - // Hide all but Yes, No - this.Button_Yes.Visibility = Visibility.Visible; - this.Button_Yes.Focus(); - this.Button_No.Visibility = Visibility.Visible; - - this.Button_OK.Visibility = Visibility.Collapsed; - this.Button_Cancel.Visibility = Visibility.Collapsed; - break; - - case MessageBoxButton.YesNoCancel: - // Hide only OK - this.Button_Yes.Visibility = Visibility.Visible; - this.Button_Yes.Focus(); - this.Button_No.Visibility = Visibility.Visible; - this.Button_Cancel.Visibility = Visibility.Visible; - - this.Button_OK.Visibility = Visibility.Collapsed; - break; - - default: - // Hide all but OK - this.Button_OK.Visibility = Visibility.Visible; - this.Button_OK.Focus(); - - this.Button_Yes.Visibility = Visibility.Collapsed; - this.Button_No.Visibility = Visibility.Collapsed; - this.Button_Cancel.Visibility = Visibility.Collapsed; - break; - } - } - - private void Button_OK_Click(object sender, RoutedEventArgs e) - { - this.Result = MessageBoxResult.OK; - this.Close(); - } - - private void Button_Cancel_Click(object sender, RoutedEventArgs e) - { - this.Result = MessageBoxResult.Cancel; - this.Close(); - } - - private void Button_Yes_Click(object sender, RoutedEventArgs e) - { - this.Result = MessageBoxResult.Yes; - this.Close(); - } - - private void Button_No_Click(object sender, RoutedEventArgs e) - { - this.Result = MessageBoxResult.No; - this.Close(); - } - - #endregion - } -} diff --git a/source/WPFCustomMessageBox/MessageBoxData.cs b/source/WPFCustomMessageBox/MessageBoxData.cs deleted file mode 100644 index 450b686..0000000 --- a/source/WPFCustomMessageBox/MessageBoxData.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Threading; -using System.Windows; -using System.Windows.Media; - -namespace WPFCustomMessageBox -{ - internal class MessageBoxData - { - #region Properties - - public Window Owner { get; set; } - - public string Message { get; set; } = ""; - - public string Caption { get; set; } = "Message"; - - public MessageBoxButton Buttons { get; set; } = MessageBoxButton.OK; - - public MessageBoxImage Image { get; set; } = MessageBoxImage.None; - - public ImageSource Icon { get; set; } - - public string YesButtonCaption { get; set; } - - public string NoButtonCaption { get; set; } - - public string CancelButtonCaption { get; set; } - - public string OkButtonCaption { get; set; } - - public MessageBoxResult Result { get; set; } = MessageBoxResult.None; - - private static Dictionary IconLookup { get; } = new Dictionary() - { - { MessageBoxImage.None, null }, - { MessageBoxImage.Error, SystemIcons.Hand }, // Hand, Stop and Error share the same value '16' - { MessageBoxImage.Question, SystemIcons.Question }, - { MessageBoxImage.Warning, SystemIcons.Warning }, // Exclamation and Warning share the same value '48' - { MessageBoxImage.Information, SystemIcons.Information } // Information and Asterisk share the same value '64' - }; - - #endregion - - #region Methods - - /// - /// Displays a message box that is defined by the properties of this class. - /// In case the current thread is not a STA thread already, - /// a new STA thread is being created and the MessageBox is being displayed from there. - /// - /// - public MessageBoxResult ShowMessageBox() - { - if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) - { - this.ShowMessageBoxSTA(); - } - else - { - var thread = new Thread(this.ShowMessageBoxSTA); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - thread.Join(); - } - - return this.Result; - } - - private void ShowMessageBoxSTA() - { - this.Icon = this.Icon ?? MessageBoxData.IconLookup[this.Image].ToImageSource(); - - var msg = new CustomMessageBoxWindow(this.Message, this.Caption, this.Buttons, this.Icon); - - msg.YesButtonText = this.YesButtonCaption ?? msg.YesButtonText; - msg.NoButtonText = this.NoButtonCaption ?? msg.NoButtonText; - msg.CancelButtonText = this.CancelButtonCaption ?? msg.CancelButtonText; - msg.OkButtonText = this.OkButtonCaption ?? msg.OkButtonText; - msg.Owner = this.Owner ?? msg.Owner; - - msg.ShowDialog(); - - this.Result = msg.Result; - } - - #endregion - } -} diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs new file mode 100644 index 0000000..fad0b39 --- /dev/null +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -0,0 +1,138 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace WPFCustomMessageBox +{ + /// + /// Model that can be used to configure and the show message boxes + /// + public class MessageBoxModel + { + #region Properties + + /// + /// Owner window + /// + public Window Owner { get; set; } + + /// + /// Message to be displayed + /// + public string Message { get; set; } = ""; + + /// + /// Caption of the message box + /// + public string Caption { get; set; } = "Message"; + + /// + /// Buttons to show + /// + public MessageBoxButton Buttons { get; set; } = MessageBoxButton.OK; + + /// + /// Image that should be shown + /// + public MessageBoxImage Image { get; set; } = MessageBoxImage.None; + + /// + /// Custom image that should be shown. + /// Must be 32x32 pixels in size. + /// This property overwrites the @Image property if it is not null. + /// + public ImageSource CustomImage { get; set; } + + /// + /// Caption of the 'Yes' button + /// + public string YesButtonCaption { get; set; } = "_Yes"; + + /// + /// Caption of the 'No' button + /// + public string NoButtonCaption { get; set; } = "_No"; + + /// + /// Caption of the 'Cancel' button + /// + public string CancelButtonCaption { get; set; } = "_Cancel"; + + /// + /// Caption of the 'OK' button + /// + public string OkButtonCaption { get; set; } = "_OK"; + + /// + /// Result of the MessageBox + /// + public MessageBoxResult Result { get; private set; } = MessageBoxResult.None; + + private static Dictionary IconLookup { get; } = new Dictionary() + { + { MessageBoxImage.None, null }, + { MessageBoxImage.Error, SystemIcons.Hand }, // Hand, Stop and Error share the same value '16' + { MessageBoxImage.Question, SystemIcons.Question }, + { MessageBoxImage.Warning, SystemIcons.Warning }, // Exclamation and Warning share the same value '48' + { MessageBoxImage.Information, SystemIcons.Information } // Information and Asterisk share the same value '64' + }; + + #endregion + + #region Methods + + /// + /// Displays a message box that is defined by the properties of this class. + /// In case the current thread is not a STA thread already, + /// a new STA thread is being created and the MessageBox is being displayed from there. + /// This method is blocking until user input. + /// + /// + public MessageBoxResult ShowDialog() + { + this.Show().Wait(); + + return this.Result; + } + + /// + /// Displays a message box that is defined by the properties of this class. + /// In case the current thread is not a STA thread already, + /// a new STA thread is being created and the MessageBox is being displayed from there. + /// This method is not blocking. + /// + /// Task that will complete once the user closes the message box + public Task Show() + { + if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) + { + return Task.Factory.StartNew(() => this.ShowMessageBoxSTA()); + } + + var thread = new Thread(this.ShowMessageBoxSTA); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + return Task.Factory.StartNew(() => thread.Join()); + } + + private void ShowMessageBoxSTA() + { + if (this.CustomImage is null) + { + this.CustomImage = MessageBoxModel.IconLookup[this.Image].ToImageSource(); + } + + var msg = new CustomMessageBoxView(); + msg.DataContext = msg; + msg.ShowDialog(); + } + + #endregion + } +} diff --git a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj index 83a6617..248d65e 100644 --- a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj +++ b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj @@ -45,13 +45,13 @@ - - CustomMessageBoxWindow.xaml + + CustomMessageBoxView.xaml - + - + Designer MSBuild:Compile From 470af5aa6f7b4b1febc4830ade89eab5c9c01a5e Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sun, 18 Dec 2022 08:36:24 +0100 Subject: [PATCH 06/14] Convert MessageBox to MVVM style --- .../CustomMessageBox Demo.csproj | 3 + .../CustomMessageBoxDemo/MainWindow.xaml.cs | 40 ++-- .../WPFCustomMessageBox/ButtonClickCommand.cs | 31 ++++ .../WPFCustomMessageBox/CustomMessageBox.cs | 148 ++------------- .../CustomMessageBoxView.xaml | 23 +-- .../CustomMessageBoxView.xaml.cs | 20 -- .../CustomMessageBoxViewModel.cs | 42 +++++ source/WPFCustomMessageBox/MessageBoxModel.cs | 171 +++++++++++++++--- .../WPFCustomMessageBox.csproj | 7 + 9 files changed, 285 insertions(+), 200 deletions(-) create mode 100644 source/WPFCustomMessageBox/ButtonClickCommand.cs create mode 100644 source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs diff --git a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj index f1b6324..539d14c 100644 --- a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj +++ b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj @@ -19,10 +19,13 @@ AnyCPU bin\Debug\ + DEBUG + true AnyCPU bin\Release\ + true diff --git a/source/CustomMessageBoxDemo/MainWindow.xaml.cs b/source/CustomMessageBoxDemo/MainWindow.xaml.cs index 2745880..1bbbc01 100644 --- a/source/CustomMessageBoxDemo/MainWindow.xaml.cs +++ b/source/CustomMessageBoxDemo/MainWindow.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Drawing; using System.Windows; using System.Windows.Interop; @@ -19,56 +20,73 @@ public MainWindow() private void button_StandardMessage_Click(object sender, RoutedEventArgs e) { - MessageBox.Show("Hello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\n"); + var result = MessageBox.Show("Hello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\n"); + Debug.WriteLine(result.ToString()); } private void button_StandardMessageNew_Click(object sender, RoutedEventArgs e) { - CustomMessageBox.Show("Hello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\n"); + var result = CustomMessageBox.Show("Hello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\nHello World!\nHello World\n"); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaption_Click(object sender, RoutedEventArgs e) { - MessageBox.Show("Hello World!", "Hello World the title."); + var result = MessageBox.Show("Hello World!", "Hello World the title."); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionNew_Click(object sender, RoutedEventArgs e) { - CustomMessageBox.Show("Hello world!", "Hello World the title."); + var result = CustomMessageBox.Show("Hello world!", "Hello World the title."); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionAndButton_Click(object sender, RoutedEventArgs e) { - MessageBox.Show("Hello World!", "Hello World the title.", MessageBoxButton.OKCancel); + var result = MessageBox.Show("Hello World!", "Hello World the title.", MessageBoxButton.OKCancel); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionAndButtonNew_Click(object sender, RoutedEventArgs e) { - CustomMessageBox.Show("Hello World!", "Hello World the title.", MessageBoxButton.OKCancel); + var result = CustomMessageBox.Show("Hello World!", "Hello World the title.", MessageBoxButton.OKCancel); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionButtonImage_Click(object sender, RoutedEventArgs e) { - MessageBox.Show( + var result = MessageBox.Show( "Are you sure you want to eject the nuclear fuel rods?", "Confirm Fuel Ejection", MessageBoxButton.OKCancel, MessageBoxImage.Exclamation); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionButtonImageNew_Click(object sender, RoutedEventArgs e) { - CustomMessageBox.Show("This is a message.", "This is a caption", MessageBoxButton.YesNo, MessageBoxImage.Asterisk); + var result = CustomMessageBox.Show("This is a message.", "This is a caption", MessageBoxButton.YesNo, MessageBoxImage.Asterisk); + Debug.WriteLine(result.ToString()); } private void button_MessageWithCaptionButtonCustomImageNew_Click(object sender, RoutedEventArgs e) { - var winLogo = Imaging.CreateBitmapSourceFromHIcon( + var shield = Imaging.CreateBitmapSourceFromHIcon( SystemIcons.Shield.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); - CustomMessageBox.Show("This is a message with a windows shield beside it.", "This is a caption", MessageBoxButton.YesNo, winLogo); + var msgBox = new MessageBoxModel() + { + Message = "This is a message with a windows shield beside it.", + Caption = "This is a caption", + Buttons = MessageBoxButton.YesNo, + CustomImage = shield + }; + var result = msgBox.ShowDialog(); + + Debug.WriteLine(result.ToString()); } private void Window_Loaded(object sender, RoutedEventArgs e) @@ -86,7 +104,7 @@ private void button1_Click(object sender, RoutedEventArgs e) "Cancel", MessageBoxImage.Exclamation); - Console.WriteLine(result); + Debug.WriteLine(result); } } } diff --git a/source/WPFCustomMessageBox/ButtonClickCommand.cs b/source/WPFCustomMessageBox/ButtonClickCommand.cs new file mode 100644 index 0000000..1d5bbe4 --- /dev/null +++ b/source/WPFCustomMessageBox/ButtonClickCommand.cs @@ -0,0 +1,31 @@ +using System; +using System.Windows; +using System.Windows.Input; + +namespace WPFCustomMessageBox +{ + internal class ButtonClickCommand : ICommand + { + public event EventHandler CanExecuteChanged; + + public Action Action { get; set; } + + public MessageBoxResult Parameter { get; set; } = MessageBoxResult.None; + + public ButtonClickCommand() + { + + } + + public ButtonClickCommand(Action action) + { + this.Action = action; + } + + public bool CanExecute(object parameter) + => (this.Action != null); + + public void Execute(object parameter) + => this.Action.Invoke(this.Parameter); + } +} diff --git a/source/WPFCustomMessageBox/CustomMessageBox.cs b/source/WPFCustomMessageBox/CustomMessageBox.cs index 8cef9bd..fd94eee 100644 --- a/source/WPFCustomMessageBox/CustomMessageBox.cs +++ b/source/WPFCustomMessageBox/CustomMessageBox.cs @@ -26,7 +26,7 @@ public static MessageBoxResult Show(string messageBoxText) Message = messageBoxText }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -43,7 +43,7 @@ public static MessageBoxResult Show(string messageBoxText, string caption) Caption = caption }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -60,7 +60,7 @@ public static MessageBoxResult Show(Window owner, string messageBoxText) Owner = owner }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -79,7 +79,7 @@ public static MessageBoxResult Show(Window owner, string messageBoxText, string Owner = owner }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -98,7 +98,7 @@ public static MessageBoxResult Show(string messageBoxText, string caption, Messa Buttons = button }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -119,28 +119,7 @@ public static MessageBoxResult Show(string messageBoxText, string caption, Messa Image = icon }; - return msgData.ShowMessageBox(); - } - - /// - /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. - /// - /// A System.String that specifies the text to display. - /// A System.String that specifies the title bar caption to display. - /// A System.Windows.MessageBoxButton value that specifies which button or buttons to display. - /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. - /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. - public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, ImageSource icon) - { - var msgData = new MessageBoxModel() - { - Message = messageBoxText, - Caption = caption, - Buttons = button, - Icon = icon - }; - - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -160,7 +139,7 @@ public static MessageBoxResult ShowOK(string messageBoxText, string caption, str OkButtonCaption = okButtonText }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -182,29 +161,7 @@ public static MessageBoxResult ShowOK(string messageBoxText, string caption, str OkButtonCaption = okButtonText }; - return msgData.ShowMessageBox(); - } - - /// - /// Displays a message box that has a message, title bar caption, OK button with a custom System.String value for the button's text, and icon; and that returns a result. - /// - /// A System.String that specifies the text to display. - /// A System.String that specifies the title bar caption to display. - /// A System.String that specifies the text to display within the OK button. - /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. - /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. - public static MessageBoxResult ShowOK(string messageBoxText, string caption, string okButtonText, ImageSource icon) - { - var msgData = new MessageBoxModel() - { - Message = messageBoxText, - Caption = caption, - Buttons = MessageBoxButton.OK, - Icon = icon, - OkButtonCaption = okButtonText - }; - - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -227,7 +184,7 @@ public static MessageBoxResult ShowOKCancel(string messageBoxText, string captio CancelButtonCaption = cancelButtonText }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -252,32 +209,7 @@ public static MessageBoxResult ShowOKCancel(string messageBoxText, string captio CancelButtonCaption = cancelButtonText }; - return msgData.ShowMessageBox(); - } - - /// - /// Displays a message box that has a message, caption, OK/Cancel buttons with custom System.String values for the buttons' text, and icon; - /// and that returns a result. - /// - /// A System.String that specifies the text to display. - /// A System.String that specifies the title bar caption to display. - /// A System.String that specifies the text to display within the OK button. - /// A System.String that specifies the text to display within the Cancel button. - /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. - /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. - public static MessageBoxResult ShowOKCancel(string messageBoxText, string caption, string okButtonText, string cancelButtonText, ImageSource icon) - { - var msgData = new MessageBoxModel() - { - Message = messageBoxText, - Caption = caption, - Buttons = MessageBoxButton.OKCancel, - Icon = icon, - OkButtonCaption = okButtonText, - CancelButtonCaption = cancelButtonText - }; - - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -300,7 +232,7 @@ public static MessageBoxResult ShowYesNo(string messageBoxText, string caption, NoButtonCaption = noButtonText }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -325,32 +257,7 @@ public static MessageBoxResult ShowYesNo(string messageBoxText, string caption, NoButtonCaption = noButtonText }; - return msgData.ShowMessageBox(); - } - - /// - /// Displays a message box that has a message, caption, Yes/No buttons with custom System.String values for the buttons' text, and icon; - /// and that returns a result. - /// - /// A System.String that specifies the text to display. - /// A System.String that specifies the title bar caption to display. - /// A System.String that specifies the text to display within the Yes button. - /// A System.String that specifies the text to display within the No button. - /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. - /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. - public static MessageBoxResult ShowYesNo(string messageBoxText, string caption, string yesButtonText, string noButtonText, ImageSource icon) - { - var msgData = new MessageBoxModel() - { - Message = messageBoxText, - Caption = caption, - Buttons = MessageBoxButton.YesNo, - Icon = icon, - YesButtonCaption = yesButtonText, - NoButtonCaption = noButtonText - }; - - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -375,7 +282,7 @@ public static MessageBoxResult ShowYesNoCancel(string messageBoxText, string cap CancelButtonCaption = cancelButtonText }; - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } /// @@ -402,34 +309,7 @@ public static MessageBoxResult ShowYesNoCancel(string messageBoxText, string cap CancelButtonCaption = cancelButtonText }; - return msgData.ShowMessageBox(); - } - - /// - /// Displays a message box that has a message, caption, Yes/No/Cancel buttons with custom System.String values for the buttons' text, and icon; - /// and that returns a result. - /// - /// A System.String that specifies the text to display. - /// A System.String that specifies the title bar caption to display. - /// A System.String that specifies the text to display within the Yes button. - /// A System.String that specifies the text to display within the No button. - /// A System.String that specifies the text to display within the Cancel button. - /// A System.Windows.ImageSource object that should be displayed besides the text. The size must be 32x32 pixels. - /// A System.Windows.MessageBoxResult value that specifies which message box button is clicked by the user. - public static MessageBoxResult ShowYesNoCancel(string messageBoxText, string caption, string yesButtonText, string noButtonText, string cancelButtonText, ImageSource icon) - { - var msgData = new MessageBoxModel() - { - Message = messageBoxText, - Caption = caption, - Buttons = MessageBoxButton.YesNoCancel, - Icon = icon, - YesButtonCaption = yesButtonText, - NoButtonCaption = noButtonText, - CancelButtonCaption = cancelButtonText - }; - - return msgData.ShowMessageBox(); + return msgData.ShowDialog(); } } } diff --git a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml index be2dad0..9ccfdb6 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml +++ b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml @@ -1,4 +1,4 @@ - + Title="{Binding Caption}" MaxHeight="{Binding MaxHeight}" MinHeight="155" MaxWidth="{Binding MaxWidth}" MinWidth="154"> @@ -25,26 +25,27 @@ - - + - - + - - + diff --git a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs index 673f196..dcf46a0 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml.cs @@ -3,31 +3,11 @@ namespace WPFCustomMessageBox { - /// - /// Interaction logic for ModalDialog.xaml - /// internal partial class CustomMessageBoxView : Window { internal CustomMessageBoxView() { this.InitializeComponent(); } - - internal void ButtonClick(object sender, RoutedEventArgs e) - { - switch ((e.Source as Button)?.Name) - { - case "FirstButton": - break; - case "SecondButton": - break; - case "ThirdButton": - break; - default: - break; - } - - this.Close(); - } } } diff --git a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs new file mode 100644 index 0000000..5e875e2 --- /dev/null +++ b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs @@ -0,0 +1,42 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; + +namespace WPFCustomMessageBox +{ + internal class CustomMessageBoxViewModel + { + public double MaxWidth { get; set; } = 470; + + public double MaxHeight { get; set; } = 900; + + public string Caption { get; set; } = string.Empty; + + public ImageSource CustomImage { get; set; } + + public Visibility ImageVisibility => (this.CustomImage is null) ? Visibility.Collapsed : Visibility.Visible; + + public string Message { get; set; } = string.Empty; + + public double ButtonMaxWidth { get; set; } = 160; + + public string FirstButtonCaption { get; set; } = string.Empty; + + public string SecondButtonCaption { get; set; } = string.Empty; + + public string ThirdButtonCaption { get; set; } = string.Empty; + + public Visibility SecondButtonVisibility => string.IsNullOrEmpty(this.SecondButtonCaption) ? Visibility.Collapsed : Visibility.Visible; + + public Visibility ThirdButtonVisibility => string.IsNullOrEmpty(this.ThirdButtonCaption) ? Visibility.Collapsed : Visibility.Visible; + + public ButtonClickCommand FirstButtonClick { get; set; } + + public ButtonClickCommand SecondButtonClick { get; set; } + + public ButtonClickCommand ThirdButtonClick { get; set; } + + public Dock FirstButtonDock { get; set; } + } +} diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index fad0b39..6ae17b9 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Threading; @@ -16,6 +17,33 @@ public class MessageBoxModel { #region Properties + /// + /// Maximum window height + /// + public double MaxHeight + { + get => this.ViewModel.MaxHeight; + set => this.ViewModel.MaxHeight = Math.Min(Math.Max(value, 0), 10000); + } + + /// + /// Maximum window width + /// + public double MaxWidth + { + get => this.ViewModel.MaxWidth; + set => this.ViewModel.MaxWidth = Math.Min(Math.Max(value, 0), 10000); + } + + /// + /// Maximum button width + /// + public double MaxButtonWidth + { + get => this.ViewModel.ButtonMaxWidth; + set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 0), 10000); + } + /// /// Owner window /// @@ -24,12 +52,20 @@ public class MessageBoxModel /// /// Message to be displayed /// - public string Message { get; set; } = ""; + public string Message + { + get => this.ViewModel.Message; + set => this.ViewModel.Message = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// Caption of the message box /// - public string Caption { get; set; } = "Message"; + public string Caption + { + get => this.ViewModel.Caption; + set => this.ViewModel.Caption = value ?? throw new ArgumentNullException(nameof(value)); + } /// /// Buttons to show @@ -51,28 +87,34 @@ public class MessageBoxModel /// /// Caption of the 'Yes' button /// - public string YesButtonCaption { get; set; } = "_Yes"; + public string YesButtonCaption { get; set; } = "Yes"; /// /// Caption of the 'No' button /// - public string NoButtonCaption { get; set; } = "_No"; + public string NoButtonCaption { get; set; } = "No"; /// /// Caption of the 'Cancel' button /// - public string CancelButtonCaption { get; set; } = "_Cancel"; + public string CancelButtonCaption { get; set; } = "Cancel"; /// /// Caption of the 'OK' button /// - public string OkButtonCaption { get; set; } = "_OK"; + public string OkButtonCaption { get; set; } = "OK"; /// /// Result of the MessageBox /// public MessageBoxResult Result { get; private set; } = MessageBoxResult.None; + private event Action RequestClosingEvent; + + private ManualResetEvent WindowClosedEvent { get; } = new ManualResetEvent(true); + + private CustomMessageBoxViewModel ViewModel { get; } + private static Dictionary IconLookup { get; } = new Dictionary() { { MessageBoxImage.None, null }, @@ -84,6 +126,23 @@ public class MessageBoxModel #endregion + #region Constructor + + /// + /// Constructor + /// + public MessageBoxModel() + { + this.ViewModel = new CustomMessageBoxViewModel() + { + FirstButtonClick = new ButtonClickCommand(this.SetResult), + SecondButtonClick = new ButtonClickCommand(this.SetResult), + ThirdButtonClick = new ButtonClickCommand(this.SetResult) + }; + } + + #endregion + #region Methods /// @@ -95,7 +154,19 @@ public class MessageBoxModel /// public MessageBoxResult ShowDialog() { - this.Show().Wait(); + this.ConfigureViewModel(); + + if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) + { + this.ShowDialogSTA(); + } + else + { + var thread = new Thread(this.ShowDialogSTA); + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + thread.Join(); + } return this.Result; } @@ -107,32 +178,84 @@ public MessageBoxResult ShowDialog() /// This method is not blocking. /// /// Task that will complete once the user closes the message box - public Task Show() + public Task Show() + => Task.Factory.StartNew(() => this.ShowDialog()); + + /// + /// Closes the current message box if it is still open + /// + public void Close() { - if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) - { - return Task.Factory.StartNew(() => this.ShowMessageBoxSTA()); - } + this.RequestClosingEvent.Invoke(); + this.WindowClosedEvent.WaitOne(); + } + + private void ShowDialogSTA() + { + var msg = new CustomMessageBoxView(); + msg.Owner = this.Owner; + msg.DataContext = this.ViewModel; + msg.Closed += this.MessageBoxClosed; - var thread = new Thread(this.ShowMessageBoxSTA); - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); + this.RequestClosingEvent = null; + this.RequestClosingEvent += new Action(() => { + msg?.Close(); msg = null; + }); - return Task.Factory.StartNew(() => thread.Join()); + msg.ShowDialog(); } - private void ShowMessageBoxSTA() + private void ConfigureViewModel() { - if (this.CustomImage is null) + // Set image + this.ViewModel.CustomImage = this.CustomImage ?? MessageBoxModel.IconLookup[this.Image]?.ToImageSource(); + + // Set buttons + switch (this.Buttons) { - this.CustomImage = MessageBoxModel.IconLookup[this.Image].ToImageSource(); + case MessageBoxButton.OKCancel: + this.ViewModel.FirstButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.SecondButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.OK; + this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.Cancel; + this.ViewModel.FirstButtonDock = Dock.Left; + break; + + case MessageBoxButton.YesNoCancel: + this.ViewModel.FirstButtonCaption = this.YesButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.SecondButtonCaption = this.NoButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.ThirdButtonCaption = this.CancelButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.Yes; + this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.No; + this.ViewModel.ThirdButtonClick.Parameter = MessageBoxResult.Cancel; + break; + + case MessageBoxButton.YesNo: + this.ViewModel.FirstButtonCaption = this.YesButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.SecondButtonCaption = this.NoButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.Yes; + this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.No; + break; + + default: //MessageBoxButton.OK + this.ViewModel.FirstButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); + this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.OK; + this.ViewModel.FirstButtonDock = Dock.Left; + break; } + } - var msg = new CustomMessageBoxView(); - msg.DataContext = msg; - msg.ShowDialog(); + private void SetResult(MessageBoxResult result) + { + this.Result = result; + this.Close(); } - + + private void MessageBoxClosed(object sender, EventArgs e) + { + this.WindowClosedEvent.Set(); + } + #endregion } } diff --git a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj index 248d65e..9363030 100644 --- a/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj +++ b/source/WPFCustomMessageBox/WPFCustomMessageBox.csproj @@ -26,11 +26,16 @@ AnyCPU bin\Debug\ bin\Debug\WPFCustomMessageBox.XML + DEBUG + true + CS0067 AnyCPU bin\Release\ bin\Release\WPFCustomMessageBox.XML + true + CS0067 @@ -49,7 +54,9 @@ CustomMessageBoxView.xaml + + Designer From 2bdc1169210b5fa320722e78602a87474c13c811 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Sun, 18 Dec 2022 10:52:49 +0100 Subject: [PATCH 07/14] Add self updating message box. Allow the caption and message to change while to messagebox is open --- .../CustomMessageBox Demo.csproj | 5 +-- source/CustomMessageBoxDemo/MainWindow.xaml | 3 +- .../CustomMessageBoxDemo/MainWindow.xaml.cs | 29 ++++++++++++-- .../Properties/Resources.Designer.cs | 4 +- .../Properties/Settings.Designer.cs | 4 +- source/CustomMessageBoxDemo/app.config | 2 +- .../CustomMessageBoxViewModel.cs | 38 +++++++++++++++++-- 7 files changed, 68 insertions(+), 17 deletions(-) diff --git a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj index 539d14c..3c5efc7 100644 --- a/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj +++ b/source/CustomMessageBoxDemo/CustomMessageBox Demo.csproj @@ -1,5 +1,5 @@  - + Debug x86 @@ -10,8 +10,7 @@ Properties CustomMessageBoxDemo CustomMessageBoxDemo - v4.0 - Client + v4.7.2 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 diff --git a/source/CustomMessageBoxDemo/MainWindow.xaml b/source/CustomMessageBoxDemo/MainWindow.xaml index 3c40abb..1f909fa 100644 --- a/source/CustomMessageBoxDemo/MainWindow.xaml +++ b/source/CustomMessageBoxDemo/MainWindow.xaml @@ -2,7 +2,7 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowStartupLocation="CenterScreen" - Title="MainWindow" Height="296" Width="570" Loaded="Window_Loaded"> + Title="MainWindow" Height="340" Width="570" Loaded="Window_Loaded"> - + - - - + - - - + + + + + diff --git a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs index 3f7af29..8c9c6ce 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs @@ -1,15 +1,12 @@ using System.ComponentModel; using System.Windows; -using System.Windows.Controls; using System.Windows.Media; namespace WPFCustomMessageBox { internal class CustomMessageBoxViewModel : INotifyPropertyChanged { - public double MaxWidth { get; set; } = 470; - - public double MaxHeight { get; set; } = 600; + #region Properties that can be updated while the message box is open public string Caption { @@ -22,10 +19,6 @@ public string Caption } private string caption = "Message"; - public ImageSource CustomImage { get; set; } - - public Visibility ImageVisibility => (this.CustomImage is null) ? Visibility.Collapsed : Visibility.Visible; - public string Message { get => this.message; @@ -37,25 +30,91 @@ public string Message } private string message = string.Empty; + public string CancelButtonCaption + { + get => this.cancelButtonCaption; + set + { + this.cancelButtonCaption = value; + this.OnPropertyChanged(nameof(this.CancelButtonCaption)); + } + } + private string cancelButtonCaption = "_Cancel"; + + public string NoButtonCaption + { + get => this.noButtonCaption; + set + { + this.noButtonCaption = value; + this.OnPropertyChanged(nameof(this.NoButtonCaption)); + } + } + private string noButtonCaption = "_No"; + + public string YesButtonCaption + { + get => this.yesButtonCaption; + set + { + this.yesButtonCaption = value; + this.OnPropertyChanged(nameof(this.YesButtonCaption)); + } + } + private string yesButtonCaption = "_Yes"; + + public string OkButtonCaption + { + get => this.okButtonCaption; + set + { + this.okButtonCaption = value; + this.OnPropertyChanged(nameof(this.OkButtonCaption)); + } + } + private string okButtonCaption = "_OK"; + + #endregion + + #region Fixed properties + + public double MaxWidth { get; set; } = 470; + + public double MaxHeight { get; set; } = 600; + + public ImageSource CustomImage { get; set; } + + public Visibility ImageVisibility => (this.CustomImage is null) ? Visibility.Collapsed : Visibility.Visible; + + public double ButtonMinWidth { get; set; } = 88; + public double ButtonMaxWidth { get; set; } = 160; - public string FirstButtonCaption { get; set; } = string.Empty; + public double CancelButtonWidth { get; set; } = double.NaN; + + public double NoButtonWidth { get; set; } = double.NaN; + + public double YesButtonWidth { get; set; } = double.NaN; - public string SecondButtonCaption { get; set; } = string.Empty; + public double OkButtonWidth { get; set; } = double.NaN; - public string ThirdButtonCaption { get; set; } = string.Empty; + public Visibility CancelButtonVisibility { get; set; } = Visibility.Collapsed; - public Visibility SecondButtonVisibility => string.IsNullOrEmpty(this.SecondButtonCaption) ? Visibility.Collapsed : Visibility.Visible; + public Visibility NoButtonVisibility { get; set; } = Visibility.Collapsed; - public Visibility ThirdButtonVisibility => string.IsNullOrEmpty(this.ThirdButtonCaption) ? Visibility.Collapsed : Visibility.Visible; + public Visibility YesButtonVisibility { get; set; } = Visibility.Collapsed; - public ButtonClickCommand FirstButtonClick { get; set; } + public Visibility OkButtonVisibility { get; set; } = Visibility.Collapsed; - public ButtonClickCommand SecondButtonClick { get; set; } + public ButtonClickCommand CancelButtonClick { get; set; } - public ButtonClickCommand ThirdButtonClick { get; set; } + public ButtonClickCommand NoButtonClick { get; set; } - public Dock FirstButtonDock { get; set; } + public ButtonClickCommand YesButtonClick { get; set; } + + public ButtonClickCommand OkButtonClick { get; set; } + + #endregion #region INotifyPropertyChanged diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index 72aaaa1..615ca4d 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -34,6 +34,15 @@ public double MaxWidth set => this.ViewModel.MaxWidth = Math.Min(Math.Max(value, 0), 10000); } + /// + /// Minimum button width + /// + public double MinButtonWidth + { + get => this.ViewModel.ButtonMinWidth; + set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 0), 10000); + } + /// /// Maximum button width /// @@ -43,6 +52,42 @@ public double MaxButtonWidth set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 0), 10000); } + /// + /// Cancel button width (double.NaN for 'Auto') + /// + public double CancelButtonWidth + { + get => this.ViewModel.CancelButtonWidth; + set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 0), 10000); + } + + /// + /// No button width (double.NaN for 'Auto') + /// + public double NoButtonWidth + { + get => this.ViewModel.NoButtonWidth; + set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 0), 10000); + } + + /// + /// Yes button width (double.NaN for 'Auto') + /// + public double YesButtonWidth + { + get => this.ViewModel.YesButtonWidth; + set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 0), 10000); + } + + /// + /// OK button width (double.NaN for 'Auto') + /// + public double OkButtonWidth + { + get => this.ViewModel.OkButtonWidth; + set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 0), 10000); + } + /// /// Owner window /// @@ -84,24 +129,40 @@ public string Caption public ImageSource CustomImage { get; set; } /// - /// Caption of the 'Yes' button + /// Caption of the 'Cancel' button /// - public string YesButtonCaption { get; set; } = "Yes"; + public string CancelButtonCaption + { + get => this.ViewModel.CancelButtonCaption.TryRemoveKeyboardAccellerator(); + set => this.ViewModel.CancelButtonCaption = value.TryAddKeyboardAccellerator(); + } /// /// Caption of the 'No' button /// - public string NoButtonCaption { get; set; } = "No"; + public string NoButtonCaption + { + get => this.ViewModel.NoButtonCaption.TryRemoveKeyboardAccellerator(); + set => this.ViewModel.NoButtonCaption = value.TryAddKeyboardAccellerator(); + } /// - /// Caption of the 'Cancel' button + /// Caption of the 'Yes' button /// - public string CancelButtonCaption { get; set; } = "Cancel"; + public string YesButtonCaption + { + get => this.ViewModel.YesButtonCaption.TryRemoveKeyboardAccellerator(); + set => this.ViewModel.YesButtonCaption = value.TryAddKeyboardAccellerator(); + } /// /// Caption of the 'OK' button /// - public string OkButtonCaption { get; set; } = "OK"; + public string OkButtonCaption + { + get => this.ViewModel.OkButtonCaption.TryRemoveKeyboardAccellerator(); + set => this.ViewModel.OkButtonCaption = value.TryAddKeyboardAccellerator(); + } /// /// Result of the MessageBox @@ -134,9 +195,10 @@ public MessageBoxModel() { this.ViewModel = new CustomMessageBoxViewModel() { - FirstButtonClick = new ButtonClickCommand(this.SetResult), - SecondButtonClick = new ButtonClickCommand(this.SetResult), - ThirdButtonClick = new ButtonClickCommand(this.SetResult) + CancelButtonClick = new ButtonClickCommand(this.SetResult, MessageBoxResult.Cancel), + NoButtonClick = new ButtonClickCommand(this.SetResult, MessageBoxResult.No), + YesButtonClick = new ButtonClickCommand(this.SetResult, MessageBoxResult.Yes), + OkButtonClick = new ButtonClickCommand(this.SetResult, MessageBoxResult.OK) }; } @@ -195,6 +257,16 @@ private void ShowDialogSTA() msg.Owner = this.Owner; msg.DataContext = this.ViewModel; msg.Closed += this.MessageBoxClosed; + + // Handle focus (using non MVVM approach here because MVVM would be just far too complicated in this case) + if(this.ViewModel.OkButtonVisibility == Visibility.Visible) + { + msg.OkButton.Focus(); + } + else if(this.ViewModel.YesButtonVisibility == Visibility.Visible) + { + msg.YesButton.Focus(); + } this.RequestClosingEvent = null; this.RequestClosingEvent += new Action(() => @@ -215,33 +287,23 @@ private void ConfigureViewModel() switch (this.Buttons) { case MessageBoxButton.OKCancel: - this.ViewModel.FirstButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.SecondButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.OK; - this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.Cancel; - this.ViewModel.FirstButtonDock = Dock.Left; + this.ViewModel.OkButtonVisibility = Visibility.Visible; + this.ViewModel.CancelButtonVisibility = Visibility.Visible; break; case MessageBoxButton.YesNoCancel: - this.ViewModel.FirstButtonCaption = this.YesButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.SecondButtonCaption = this.NoButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.ThirdButtonCaption = this.CancelButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.Yes; - this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.No; - this.ViewModel.ThirdButtonClick.Parameter = MessageBoxResult.Cancel; + this.ViewModel.CancelButtonVisibility = Visibility.Visible; + this.ViewModel.NoButtonVisibility = Visibility.Visible; + this.ViewModel.YesButtonVisibility = Visibility.Visible; break; case MessageBoxButton.YesNo: - this.ViewModel.FirstButtonCaption = this.YesButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.SecondButtonCaption = this.NoButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.Yes; - this.ViewModel.SecondButtonClick.Parameter = MessageBoxResult.No; + this.ViewModel.NoButtonVisibility = Visibility.Visible; + this.ViewModel.YesButtonVisibility = Visibility.Visible; break; default: //MessageBoxButton.OK - this.ViewModel.FirstButtonCaption = this.OkButtonCaption.TryAddKeyboardAccellerator(); - this.ViewModel.FirstButtonClick.Parameter = MessageBoxResult.OK; - this.ViewModel.FirstButtonDock = Dock.Left; + this.ViewModel.OkButtonVisibility = Visibility.Visible; break; } } diff --git a/source/WPFCustomMessageBox/Util.cs b/source/WPFCustomMessageBox/Util.cs index 0780199..d45faed 100644 --- a/source/WPFCustomMessageBox/Util.cs +++ b/source/WPFCustomMessageBox/Util.cs @@ -42,9 +42,24 @@ internal static string TryAddKeyboardAccellerator(this string input) const string accellerator = "_"; // This is the default WPF accellerator symbol - used to be & in WinForms // If it already contains an accellerator, do nothing - if (input.Contains(accellerator)) return input; + if (input.StartsWith(accellerator) == true) return input; return accellerator + input; } + + /// + /// Removes the acellerator added by TryAddKeyboardAccellerator() + /// + /// + /// + internal static string TryRemoveKeyboardAccellerator(this string input) + { + const string accellerator = "_"; // This is the default WPF accellerator symbol - used to be & in WinForms + + // If it already contains an accellerator, do nothing + if (input.StartsWith(accellerator) == false) return input; + + return input.Remove(0, 1); + } } } From 730f22a464ef898157dbb663730462594da41957 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Wed, 28 Dec 2022 23:14:17 +0100 Subject: [PATCH 11/14] Allow setting the message box width and height --- .../CustomMessageBoxDemo/MainWindow.xaml.cs | 3 ++- .../CustomMessageBoxView.xaml | 2 +- .../CustomMessageBoxViewModel.cs | 4 +++ source/WPFCustomMessageBox/MessageBoxModel.cs | 26 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/source/CustomMessageBoxDemo/MainWindow.xaml.cs b/source/CustomMessageBoxDemo/MainWindow.xaml.cs index 8174a40..a299995 100644 --- a/source/CustomMessageBoxDemo/MainWindow.xaml.cs +++ b/source/CustomMessageBoxDemo/MainWindow.xaml.cs @@ -80,8 +80,9 @@ private void button_MessageWithCaptionButtonCustomImageNew_Click(object sender, var msgBox = new MessageBoxModel() { - Message = "This is a message with a windows shield beside it.", + Message = "This is a wide message with a windows shield beside it.", Caption = "This is a caption", + Width = 900, Buttons = MessageBoxButton.YesNo, CustomImage = shield }; diff --git a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml index a39ff42..590327c 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml +++ b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml @@ -7,7 +7,7 @@ Icon="{Binding CustomImage}" ShowInTaskbar="True" Topmost="True" SizeToContent="WidthAndHeight" TextOptions.TextFormattingMode="Display" TextOptions.TextRenderingMode="ClearType" UseLayoutRounding="True" - Title="{Binding Caption}" MaxHeight="{Binding MaxHeight}" MinHeight="155" MaxWidth="{Binding MaxWidth}" MinWidth="154"> + Title="{Binding Caption}" MaxHeight="{Binding MaxHeight}" MinHeight="{Binding MinHeight}" MaxWidth="{Binding MaxWidth}" MinWidth="{Binding MinWidth}"> diff --git a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs index 8c9c6ce..2936c2b 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs @@ -80,8 +80,12 @@ public string OkButtonCaption public double MaxWidth { get; set; } = 470; + public double MinWidth { get; set; } = 154; + public double MaxHeight { get; set; } = 600; + public double MinHeight { get; set; } = 155; + public ImageSource CustomImage { get; set; } public Visibility ImageVisibility => (this.CustomImage is null) ? Visibility.Collapsed : Visibility.Visible; diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index 615ca4d..e794066 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -25,6 +25,19 @@ public double MaxHeight set => this.ViewModel.MaxHeight = Math.Min(Math.Max(value, 0), 10000); } + /// + /// Window height + /// + public double Height + { + get => (this.ViewModel.MinHeight == this.ViewModel.MaxHeight) ? this.ViewModel.MinHeight : double.NaN; + set + { + this.MaxHeight = value; + this.ViewModel.MinHeight = this.MaxHeight; + } + } + /// /// Maximum window width /// @@ -34,6 +47,19 @@ public double MaxWidth set => this.ViewModel.MaxWidth = Math.Min(Math.Max(value, 0), 10000); } + /// + /// Window width + /// + public double Width + { + get => (this.ViewModel.MinWidth == this.ViewModel.MaxWidth) ? this.ViewModel.MinWidth : double.NaN; + set + { + this.MaxWidth = value; + this.ViewModel.MinWidth = this.MaxWidth; + } + } + /// /// Minimum button width /// From aa6493f0b614409ca2cf45174403a76997be0f46 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Wed, 28 Dec 2022 23:29:42 +0100 Subject: [PATCH 12/14] set minimum values --- source/WPFCustomMessageBox/MessageBoxModel.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index e794066..9772b3d 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; -using System.Windows.Controls; using System.Windows.Media; namespace WPFCustomMessageBox @@ -22,7 +21,7 @@ public class MessageBoxModel public double MaxHeight { get => this.ViewModel.MaxHeight; - set => this.ViewModel.MaxHeight = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.MaxHeight = Math.Min(Math.Max(value, 155), 10000); } /// @@ -44,7 +43,7 @@ public double Height public double MaxWidth { get => this.ViewModel.MaxWidth; - set => this.ViewModel.MaxWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.MaxWidth = Math.Min(Math.Max(value, 154), 10000); } /// @@ -66,7 +65,7 @@ public double Width public double MinButtonWidth { get => this.ViewModel.ButtonMinWidth; - set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -75,7 +74,7 @@ public double MinButtonWidth public double MaxButtonWidth { get => this.ViewModel.ButtonMaxWidth; - set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -84,7 +83,7 @@ public double MaxButtonWidth public double CancelButtonWidth { get => this.ViewModel.CancelButtonWidth; - set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -93,7 +92,7 @@ public double CancelButtonWidth public double NoButtonWidth { get => this.ViewModel.NoButtonWidth; - set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -102,7 +101,7 @@ public double NoButtonWidth public double YesButtonWidth { get => this.ViewModel.YesButtonWidth; - set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -111,7 +110,7 @@ public double YesButtonWidth public double OkButtonWidth { get => this.ViewModel.OkButtonWidth; - set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 0), 10000); + set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 30), 10000); } /// @@ -283,13 +282,13 @@ private void ShowDialogSTA() msg.Owner = this.Owner; msg.DataContext = this.ViewModel; msg.Closed += this.MessageBoxClosed; - + // Handle focus (using non MVVM approach here because MVVM would be just far too complicated in this case) - if(this.ViewModel.OkButtonVisibility == Visibility.Visible) + if (this.ViewModel.OkButtonVisibility == Visibility.Visible) { msg.OkButton.Focus(); } - else if(this.ViewModel.YesButtonVisibility == Visibility.Visible) + else if (this.ViewModel.YesButtonVisibility == Visibility.Visible) { msg.YesButton.Focus(); } From d2f761995039b9259ea0495e1728d143d6b38a72 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Wed, 28 Dec 2022 23:30:38 +0100 Subject: [PATCH 13/14] small change --- source/WPFCustomMessageBox/MessageBoxModel.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index 9772b3d..edbbef2 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -65,7 +65,7 @@ public double Width public double MinButtonWidth { get => this.ViewModel.ButtonMinWidth; - set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 26), 10000); } /// @@ -74,7 +74,7 @@ public double MinButtonWidth public double MaxButtonWidth { get => this.ViewModel.ButtonMaxWidth; - set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 26), 10000); } /// @@ -83,7 +83,7 @@ public double MaxButtonWidth public double CancelButtonWidth { get => this.ViewModel.CancelButtonWidth; - set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 26), 10000); } /// @@ -92,7 +92,7 @@ public double CancelButtonWidth public double NoButtonWidth { get => this.ViewModel.NoButtonWidth; - set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 26), 10000); } /// @@ -101,7 +101,7 @@ public double NoButtonWidth public double YesButtonWidth { get => this.ViewModel.YesButtonWidth; - set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 26), 10000); } /// @@ -110,7 +110,7 @@ public double YesButtonWidth public double OkButtonWidth { get => this.ViewModel.OkButtonWidth; - set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 30), 10000); + set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 26), 10000); } /// From cc91d55811924de030e41f1a6f5d9c5795b531f3 Mon Sep 17 00:00:00 2001 From: "DESKTOP-PTDOV23\\KaiLi" Date: Thu, 29 Dec 2022 14:02:31 +0100 Subject: [PATCH 14/14] Test changing the button widths. Fix found bugs. --- .../CustomMessageBoxDemo/MainWindow.xaml.cs | 2 + .../CustomMessageBoxView.xaml | 8 +- .../CustomMessageBoxViewModel.cs | 24 +++-- source/WPFCustomMessageBox/MessageBoxModel.cs | 98 ++++++++++++++++--- 4 files changed, 106 insertions(+), 26 deletions(-) diff --git a/source/CustomMessageBoxDemo/MainWindow.xaml.cs b/source/CustomMessageBoxDemo/MainWindow.xaml.cs index a299995..b94261f 100644 --- a/source/CustomMessageBoxDemo/MainWindow.xaml.cs +++ b/source/CustomMessageBoxDemo/MainWindow.xaml.cs @@ -83,6 +83,8 @@ private void button_MessageWithCaptionButtonCustomImageNew_Click(object sender, Message = "This is a wide message with a windows shield beside it.", Caption = "This is a caption", Width = 900, + MinButtonWidth = 40, + YesButtonWidth = 300, Buttons = MessageBoxButton.YesNo, CustomImage = shield }; diff --git a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml index 590327c..ebba4e5 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxView.xaml +++ b/source/WPFCustomMessageBox/CustomMessageBoxView.xaml @@ -26,28 +26,28 @@ - - - - diff --git a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs index 2936c2b..1d70c71 100644 --- a/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs +++ b/source/WPFCustomMessageBox/CustomMessageBoxViewModel.cs @@ -6,6 +6,14 @@ namespace WPFCustomMessageBox { internal class CustomMessageBoxViewModel : INotifyPropertyChanged { + #region Constants + + private static double ButtonMinWidth => 88; + + private static double ButtonMaxWidth => 160; + + #endregion + #region Properties that can be updated while the message box is open public string Caption @@ -90,17 +98,21 @@ public string OkButtonCaption public Visibility ImageVisibility => (this.CustomImage is null) ? Visibility.Collapsed : Visibility.Visible; - public double ButtonMinWidth { get; set; } = 88; + public double CancelButtonMinWidth { get; set; } = ButtonMinWidth; + + public double CancelButtonMaxWidth { get; set; } = ButtonMaxWidth; + + public double NoButtonMinWidth { get; set; } = ButtonMinWidth; - public double ButtonMaxWidth { get; set; } = 160; + public double NoButtonMaxWidth { get; set; } = ButtonMaxWidth; - public double CancelButtonWidth { get; set; } = double.NaN; + public double YesButtonMinWidth { get; set; } = ButtonMinWidth; - public double NoButtonWidth { get; set; } = double.NaN; + public double YesButtonMaxWidth { get; set; } = ButtonMaxWidth; - public double YesButtonWidth { get; set; } = double.NaN; + public double OkButtonMinWidth { get; set; } = ButtonMinWidth; - public double OkButtonWidth { get; set; } = double.NaN; + public double OkButtonMaxWidth { get; set; } = ButtonMaxWidth; public Visibility CancelButtonVisibility { get; set; } = Visibility.Collapsed; diff --git a/source/WPFCustomMessageBox/MessageBoxModel.cs b/source/WPFCustomMessageBox/MessageBoxModel.cs index edbbef2..eff0a98 100644 --- a/source/WPFCustomMessageBox/MessageBoxModel.cs +++ b/source/WPFCustomMessageBox/MessageBoxModel.cs @@ -13,6 +13,14 @@ namespace WPFCustomMessageBox /// public class MessageBoxModel { + #region Constants + + private static double ButtonMinWidth => 26; + + private static double ButtonMaxWidth => 2000; + + #endregion + #region Properties /// @@ -60,21 +68,63 @@ public double Width } /// - /// Minimum button width + /// Maximum button width. + /// This overwrites custom button widths. + /// If both should be changed, please set the max button width first and then change the width of selected buttons. /// - public double MinButtonWidth + public double MaxButtonWidth { - get => this.ViewModel.ButtonMinWidth; - set => this.ViewModel.ButtonMinWidth = Math.Min(Math.Max(value, 26), 10000); + get + { + if ((this.ViewModel.CancelButtonMaxWidth == this.ViewModel.OkButtonMaxWidth) + && (this.ViewModel.NoButtonMaxWidth == this.ViewModel.OkButtonMaxWidth) + && (this.ViewModel.YesButtonMaxWidth == this.ViewModel.OkButtonMaxWidth)) + { + return this.ViewModel.OkButtonMaxWidth; + } + return double.NaN; + } + set + { + this.ViewModel.OkButtonMaxWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.OkButtonMinWidth = Math.Min(this.ViewModel.OkButtonMinWidth, this.ViewModel.OkButtonMaxWidth); + this.ViewModel.CancelButtonMaxWidth = this.ViewModel.OkButtonMaxWidth; + this.ViewModel.CancelButtonMinWidth = Math.Min(this.ViewModel.CancelButtonMinWidth, this.ViewModel.OkButtonMaxWidth); + this.ViewModel.NoButtonMaxWidth = this.ViewModel.OkButtonMaxWidth; + this.ViewModel.NoButtonMinWidth = Math.Min(this.ViewModel.NoButtonMinWidth, this.ViewModel.OkButtonMaxWidth); + this.ViewModel.YesButtonMaxWidth = this.ViewModel.OkButtonMaxWidth; + this.ViewModel.YesButtonMinWidth = Math.Min(this.ViewModel.YesButtonMinWidth, this.ViewModel.OkButtonMaxWidth); + } } /// - /// Maximum button width + /// Minimum button width. + /// This overwrites custom button widths. + /// If both should be changed, please set the min button width first and then change the width of selected buttons. /// - public double MaxButtonWidth + public double MinButtonWidth { - get => this.ViewModel.ButtonMaxWidth; - set => this.ViewModel.ButtonMaxWidth = Math.Min(Math.Max(value, 26), 10000); + get + { + if ((this.ViewModel.CancelButtonMinWidth == this.ViewModel.OkButtonMinWidth) + && (this.ViewModel.NoButtonMinWidth == this.ViewModel.OkButtonMinWidth) + && (this.ViewModel.YesButtonMinWidth == this.ViewModel.OkButtonMinWidth)) + { + return this.ViewModel.OkButtonMinWidth; + } + return double.NaN; + } + set + { + this.ViewModel.OkButtonMinWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.OkButtonMaxWidth = Math.Max(this.ViewModel.OkButtonMaxWidth, this.ViewModel.OkButtonMinWidth); + this.ViewModel.CancelButtonMinWidth = this.ViewModel.OkButtonMinWidth; + this.ViewModel.CancelButtonMaxWidth = Math.Min(this.ViewModel.CancelButtonMaxWidth, this.ViewModel.OkButtonMinWidth); + this.ViewModel.NoButtonMinWidth = this.ViewModel.OkButtonMinWidth; + this.ViewModel.NoButtonMaxWidth = Math.Min(this.ViewModel.NoButtonMaxWidth, this.ViewModel.OkButtonMinWidth); + this.ViewModel.YesButtonMinWidth = this.ViewModel.OkButtonMinWidth; + this.ViewModel.YesButtonMaxWidth = Math.Min(this.ViewModel.YesButtonMaxWidth, this.ViewModel.OkButtonMinWidth); + } } /// @@ -82,8 +132,12 @@ public double MaxButtonWidth /// public double CancelButtonWidth { - get => this.ViewModel.CancelButtonWidth; - set => this.ViewModel.CancelButtonWidth = Math.Min(Math.Max(value, 26), 10000); + get => (this.ViewModel.CancelButtonMinWidth == this.ViewModel.CancelButtonMaxWidth) ? this.ViewModel.CancelButtonMinWidth : double.NaN; + set + { + this.ViewModel.CancelButtonMaxWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.CancelButtonMinWidth = this.ViewModel.CancelButtonMaxWidth; + } } /// @@ -91,8 +145,12 @@ public double CancelButtonWidth /// public double NoButtonWidth { - get => this.ViewModel.NoButtonWidth; - set => this.ViewModel.NoButtonWidth = Math.Min(Math.Max(value, 26), 10000); + get => (this.ViewModel.NoButtonMinWidth == this.ViewModel.NoButtonMaxWidth) ? this.ViewModel.NoButtonMinWidth : double.NaN; + set + { + this.ViewModel.NoButtonMaxWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.NoButtonMinWidth = this.ViewModel.NoButtonMaxWidth; + } } /// @@ -100,8 +158,12 @@ public double NoButtonWidth /// public double YesButtonWidth { - get => this.ViewModel.YesButtonWidth; - set => this.ViewModel.YesButtonWidth = Math.Min(Math.Max(value, 26), 10000); + get => (this.ViewModel.YesButtonMinWidth == this.ViewModel.YesButtonMaxWidth) ? this.ViewModel.YesButtonMinWidth : double.NaN; + set + { + this.ViewModel.YesButtonMaxWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.YesButtonMinWidth = this.ViewModel.YesButtonMaxWidth; + } } /// @@ -109,8 +171,12 @@ public double YesButtonWidth /// public double OkButtonWidth { - get => this.ViewModel.OkButtonWidth; - set => this.ViewModel.OkButtonWidth = Math.Min(Math.Max(value, 26), 10000); + get => (this.ViewModel.OkButtonMinWidth == this.ViewModel.OkButtonMaxWidth) ? this.ViewModel.OkButtonMinWidth : double.NaN; + set + { + this.ViewModel.OkButtonMaxWidth = Math.Min(Math.Max(value, ButtonMinWidth), ButtonMaxWidth); + this.ViewModel.OkButtonMinWidth = this.ViewModel.OkButtonMaxWidth; + } } ///