diff --git a/ModernWpf.MessageBox.Test/App.xaml b/ModernWpf.MessageBox.Test/App.xaml index adda155..2dc6bef 100644 --- a/ModernWpf.MessageBox.Test/App.xaml +++ b/ModernWpf.MessageBox.Test/App.xaml @@ -1,9 +1,10 @@ - + diff --git a/ModernWpf.MessageBox.Test/App.xaml.cs b/ModernWpf.MessageBox.Test/App.xaml.cs index c58af09..5615c35 100644 --- a/ModernWpf.MessageBox.Test/App.xaml.cs +++ b/ModernWpf.MessageBox.Test/App.xaml.cs @@ -1,27 +1,30 @@ -using System.Windows; -using ModernWpf; +using ModernWpf; using ModernWpf.Controls; +using System.Windows; -namespace ModernWpfMessageBox.Test { - public partial class App : Application { - protected override void OnStartup(StartupEventArgs e) { +namespace ModernWpfMessageBox.Test +{ + public partial class App : Application + { + protected override void OnStartup(StartupEventArgs e) + { base.OnStartup(e); - var title = "Some title"; - var message = "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test text!"; + string title = "Some title"; + string message = "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong test text!"; - // MessageBox.Show(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); - // MessageBox.Show("adawdawda", title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + System.Windows.MessageBox.Show(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + System.Windows.MessageBox.Show("adawdawda", title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); ShutdownMode = ShutdownMode.OnExplicitShutdown; - // ModernWpf.MessageBox.Show("This is a test text!", "Some title", MessageBoxButton.YesNoCancel, MessageBoxImage.Question); - // ModernWpf.MessageBox.Show(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); - ModernWpf.MessageBox.Show("redadwada", null, MessageBoxButton.OK, Symbol.Admin); - ModernWpf.MessageBox.Show("redadwada", null, MessageBoxButton.OK, SymbolGlyph.Airplane); - ModernWpf.MessageBox.Show("redadwada", null, MessageBoxButton.OK, SymbolGlyph.Airplane, MessageBoxResult.OK); - ModernWpf.MessageBox.ShowAsync(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).GetAwaiter().GetResult(); - ModernWpf.MessageBox.ShowAsync(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Hand, MessageBoxResult.Cancel).GetAwaiter().GetResult(); - ModernWpf.MessageBox.EnableLocalization = false; - ModernWpf.MessageBox.ShowAsync("Press Alt and you should see underscores!", null, MessageBoxButton.YesNoCancel, MessageBoxImage.Hand).GetAwaiter().GetResult(); + ModernWpf.Controls.MessageBox.Show("This is a test text!", "Some title", MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + ModernWpf.Controls.MessageBox.Show(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question); + ModernWpf.Controls.MessageBox.Show("redadwada", null, MessageBoxButton.OK, ((char)Symbol.Admin).ToString()); + ModernWpf.Controls.MessageBox.Show("redadwada", null, MessageBoxButton.OK, SymbolGlyph.Airplane); + ModernWpf.Controls.MessageBox.Show("redadwada", null, MessageBoxButton.OK, SymbolGlyph.Airplane, MessageBoxResult.OK); + ModernWpf.Controls.MessageBox.ShowAsync(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Question).GetAwaiter().GetResult(); + ModernWpf.Controls.MessageBox.ShowAsync(message, title, MessageBoxButton.YesNoCancel, MessageBoxImage.Hand, MessageBoxResult.Cancel).GetAwaiter().GetResult(); + ModernWpf.Controls.MessageBox.EnableLocalization = false; + ModernWpf.Controls.MessageBox.ShowAsync("Press Alt and you should see underscores!", null, MessageBoxButton.YesNoCancel, MessageBoxImage.Hand).GetAwaiter().GetResult(); Shutdown(); } } diff --git a/ModernWpf.MessageBox.Test/ModernWpf.MessageBox.Test.csproj b/ModernWpf.MessageBox.Test/ModernWpf.MessageBox.Test.csproj index a3f7361..5bbb22c 100644 --- a/ModernWpf.MessageBox.Test/ModernWpf.MessageBox.Test.csproj +++ b/ModernWpf.MessageBox.Test/ModernWpf.MessageBox.Test.csproj @@ -2,9 +2,8 @@ WinExe - net45;net462;netcoreapp3.0;net5.0-windows10.0.18362 + net6.0-windows10.0.18362.0 True - diff --git a/ModernWpf.MessageBox/Extensions/DWMAPI.cs b/ModernWpf.MessageBox/Extensions/DWMAPI.cs new file mode 100644 index 0000000..8927f01 --- /dev/null +++ b/ModernWpf.MessageBox/Extensions/DWMAPI.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace MS.Win32 +{ + /// + /// Used by Desktop Window Manager (DWM) + /// + internal static class DWMAPI + { + /// + /// DWMWINDOWATTRIBUTE enumeration. (dwmapi.h) + /// + /// + [Flags] + public enum DWMWINDOWATTRIBUTE : uint + { + /// + /// Enables or forcibly disables DWM transitions. The pvAttribute parameter points to a value of type BOOL. TRUE to disable transitions, or FALSE to enable transitions. + /// + DWMWA_TRANSITIONS_FORCEDISABLED = 3, + + /// + /// Enables content rendered in the non-client area to be visible on the frame drawn by DWM. + /// + DWMWA_ALLOW_NCPAINT = 4, + + /// + /// Retrieves the bounds of the caption button area in the window-relative space. + /// + DWMWA_CAPTION_BUTTON_BOUNDS = 5, + + /// + /// Forces the window to display an iconic thumbnail or peek representation (a static bitmap), even if a live or snapshot representation of the window is available. + /// + DWMWA_FORCE_ICONIC_REPRESENTATION = 7, + + /// + /// Cloaks the window such that it is not visible to the user. + /// + DWMWA_CLOAK = 13, + + /// + /// If the window is cloaked, provides one of the following values explaining why. + /// + DWMWA_CLOAKED = 14, + + /// + /// Freeze the window's thumbnail image with its current visuals. Do no further live updates on the thumbnail image to match the window's contents. + /// + DWMWA_FREEZE_REPRESENTATION = 15, + + /// + /// Allows a window to either use the accent color, or dark, according to the user Color Mode preferences. + /// + DWMWA_USE_IMMERSIVE_DARK_MODE_OLD = 19, + + /// + /// Allows a window to either use the accent color, or dark, according to the user Color Mode preferences. + /// + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + + /// + /// Controls the policy that rounds top-level window corners. + /// Windows 11 and above. + /// + DWMWA_WINDOW_CORNER_PREFERENCE = 33, + + /// + /// The color of the thin border around a top-level window. + /// + DWMWA_BORDER_COLOR = 34, + + /// + /// The color of the caption. + /// Windows 11 and above. + /// + DWMWA_CAPTION_COLOR = 35, + + /// + /// The color of the caption text. + /// Windows 11 and above. + /// + DWMWA_TEXT_COLOR = 36, + + /// + /// Width of the visible border around a thick frame window. + /// Windows 11 and above. + /// + DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 37, + + /// + /// Allows to enter a value from 0 to 4 deciding on the imposed backdrop effect. + /// + DWMWA_SYSTEMBACKDROP_TYPE = 38, + + /// + /// Indicates whether the window should use the Mica effect. + /// Windows 11 and above. + /// + DWMWA_MICA_EFFECT = 1029 + } + + /// + /// Collection of backdrop types. + /// + [Flags] + public enum DWMSBT : uint + { + /// + /// Automatically selects backdrop effect. + /// + DWMSBT_AUTO = 0, + + /// + /// Turns off the backdrop effect. + /// + DWMSBT_DISABLE = 1, + + /// + /// Sets Mica effect with generated wallpaper tint. + /// + DWMSBT_MAINWINDOW = 2, + + /// + /// Sets acrlic effect. + /// + DWMSBT_TRANSIENTWINDOW = 3, + + /// + /// Sets blurred wallpaper effect, like Mica without tint. + /// + DWMSBT_TABBEDWINDOW = 4 + } + + /// + /// Abstraction of pointer to an object containing the attribute value to set. The type of the value set depends on the value of the dwAttribute parameter. + /// The DWMWINDOWATTRIBUTE enumeration topic indicates, in the row for each flag, what type of value you should pass a pointer to in the pvAttribute parameter. + /// + public enum PvAttribute + { + /// + /// Object containing the attribute value to set in dwmapi.h. + /// + Disable = 0x00, + + /// + /// Object containing the attribute value to set in dwmapi.h. + /// + Enable = 0x01 + } + + /// + /// Represents the current DWM color accent settings. + /// + public struct DWMCOLORIZATIONPARAMS + { + /// + /// ColorizationColor + /// + public uint clrColor; + + /// + /// ColorizationAfterglow. + /// + public uint clrAfterGlow; + + /// + /// ColorizationColorBalance. + /// + public uint nIntensity; + + /// + /// ColorizationAfterglowBalance. + /// + public uint clrAfterGlowBalance; + + /// + /// ColorizationBlurBalance. + /// + public uint clrBlurBalance; + + /// + /// ColorizationGlassReflectionIntensity. + /// + public uint clrGlassReflectionIntensity; + + /// + /// ColorizationOpaqueBlend. + /// + public bool fOpaque; + } + + /// + /// Sets the value of Desktop Window Manager (DWM) non-client rendering attributes for a window. + /// + /// The handle to the window for which the attribute value is to be set. + /// A flag describing which value to set, specified as a value of the DWMWINDOWATTRIBUTE enumeration. + /// A pointer to an object containing the attribute value to set. + /// The size, in bytes, of the attribute value being set via the pvAttribute parameter. + /// If the function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [DllImport("dwmapi.dll")] + public static extern int DwmSetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, + int cbAttribute); + + /// + /// The feature is not included in the Microsoft documentation. Reads Desktop Window Manager (DWM) color information. + /// + /// A pointer to a reference value that will hold the color information. + [DllImport("dwmapi.dll", EntryPoint = "#127", PreserveSig = false, CharSet = CharSet.Unicode)] + public static extern void DwmGetColorizationParameters(out DWMCOLORIZATIONPARAMS dwParameters); + } +} diff --git a/ModernWpf.MessageBox/Extensions/MessageBoxImageExtensions.cs b/ModernWpf.MessageBox/Extensions/MessageBoxImageExtensions.cs index 14c8776..6cb270d 100644 --- a/ModernWpf.MessageBox/Extensions/MessageBoxImageExtensions.cs +++ b/ModernWpf.MessageBox/Extensions/MessageBoxImageExtensions.cs @@ -1,10 +1,14 @@ using System; using System.Windows; -namespace ModernWpf.Extensions { - internal static class MessageBoxImageExtensions { - public static SymbolGlyph ToSymbol(this MessageBoxImage image) { - return image switch { +namespace ModernWpf.Extensions +{ + internal static class MessageBoxImageExtensions + { + public static SymbolGlyph ToSymbol(this MessageBoxImage image) + { + return image switch + { MessageBoxImage.Error => SymbolGlyph.Error, MessageBoxImage.Information => SymbolGlyph.Info, MessageBoxImage.Warning => SymbolGlyph.Warning, diff --git a/ModernWpf.MessageBox/Extensions/OSVersionHelper.cs b/ModernWpf.MessageBox/Extensions/OSVersionHelper.cs new file mode 100644 index 0000000..ec12334 --- /dev/null +++ b/ModernWpf.MessageBox/Extensions/OSVersionHelper.cs @@ -0,0 +1,49 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace ModernWpf +{ + internal static class OSVersionHelper + { + public static readonly Version OSVersion = GetOSVersion(); + + public static bool IsWindowsNT { get; } = Environment.OSVersion.Platform == PlatformID.Win32NT; + + public static bool IsWindowsVistaOrGreater { get; } = IsWindowsNT && OSVersion >= new Version(6, 0); + + public static bool IsWindows7OrGreater { get; } = IsWindowsNT && OSVersion >= new Version(6, 1); + + public static bool IsWindows8OrGreater { get; } = IsWindowsNT && OSVersion >= new Version(6, 2); + + public static bool IsWindows81OrGreater { get; } = IsWindowsNT && OSVersion >= new Version(6, 2); + + public static bool IsWindows10OrGreater { get; } = IsWindowsNT && OSVersion >= new Version(10, 0); + + public static bool IsWindows11OrGreater { get; } = IsWindowsNT && OSVersion >= new Version(10, 0, 21996); + + private static Version GetOSVersion() + { + var osv = new RTL_OSVERSIONINFOEX(); + osv.dwOSVersionInfoSize = (uint)Marshal.SizeOf(osv); + int ret = RtlGetVersion(out osv); + Debug.Assert(ret == 0); + return new Version((int)osv.dwMajorVersion, (int)osv.dwMinorVersion, (int)osv.dwBuildNumber); + } + + [DllImport("ntdll.dll")] + private static extern int RtlGetVersion(out RTL_OSVERSIONINFOEX lpVersionInformation); + + [StructLayout(LayoutKind.Sequential)] + private struct RTL_OSVERSIONINFOEX + { + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + internal string szCSDVersion; + } + } +} diff --git a/ModernWpf.MessageBox/Extensions/SymbolExtensions.cs b/ModernWpf.MessageBox/Extensions/SymbolExtensions.cs index 5764824..6f0b0c5 100644 --- a/ModernWpf.MessageBox/Extensions/SymbolExtensions.cs +++ b/ModernWpf.MessageBox/Extensions/SymbolExtensions.cs @@ -1,7 +1,9 @@ using ModernWpf.Controls; -namespace ModernWpf.Extensions { - internal static class SymbolExtensions { +namespace ModernWpf.Extensions +{ + internal static class SymbolExtensions + { public static string ToGlyph(this Symbol symbol) => char.ConvertFromUtf32((int)symbol); } diff --git a/ModernWpf.MessageBox/Extensions/SymbolGlyphExtensions.cs b/ModernWpf.MessageBox/Extensions/SymbolGlyphExtensions.cs index 3293b29..2074bdd 100644 --- a/ModernWpf.MessageBox/Extensions/SymbolGlyphExtensions.cs +++ b/ModernWpf.MessageBox/Extensions/SymbolGlyphExtensions.cs @@ -1,5 +1,7 @@ -namespace ModernWpf.Extensions { - internal static class SymbolGlyphExtensions { +namespace ModernWpf.Extensions +{ + internal static class SymbolGlyphExtensions + { public static string ToGlyph(this SymbolGlyph symbol) => char.ConvertFromUtf32((int)symbol); } diff --git a/ModernWpf.MessageBox/Extensions/UIExtensions.cs b/ModernWpf.MessageBox/Extensions/UIExtensions.cs new file mode 100644 index 0000000..ea0d73c --- /dev/null +++ b/ModernWpf.MessageBox/Extensions/UIExtensions.cs @@ -0,0 +1,282 @@ +using ModernWpf.Controls; +using MS.Win32; +using System; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace ModernWpf.Extensions +{ + internal static class UIExtensions + { + public static IconElement MakeIconElementFrom(this IconSource iconSource) + { + if (iconSource is FontIconSource fontIconSource) + { + FontIcon fontIcon = new FontIcon(); + + fontIcon.Glyph = fontIconSource.Glyph; + fontIcon.FontSize = fontIconSource.FontSize; + var newForeground = fontIconSource.Foreground; + if (newForeground != null) + { + fontIcon.Foreground = newForeground; + } + + if (fontIconSource.FontFamily != null) + { + fontIcon.FontFamily = fontIconSource.FontFamily; + } + + fontIcon.FontWeight = fontIconSource.FontWeight; + fontIcon.FontStyle = fontIconSource.FontStyle; + //fontIcon.IsTextScaleFactorEnabled = fontIconSource.IsTextScaleFactorEnabled; + //fontIcon.MirroredWhenRightToLeft = fontIconSource.MirroredWhenRightToLeft; + + return fontIcon; + } + else if (iconSource is SymbolIconSource symbolIconSource) + { + SymbolIcon symbolIcon = new SymbolIcon(); + symbolIcon.Symbol = symbolIconSource.Symbol; + var newForeground = symbolIconSource.Foreground; + if (newForeground != null) + { + symbolIcon.Foreground = newForeground; + } + return symbolIcon; + } + else if (iconSource is BitmapIconSource bitmapIconSource) + { + BitmapIcon bitmapIcon = new BitmapIcon(); + + if (bitmapIconSource.UriSource != null) + { + bitmapIcon.UriSource = bitmapIconSource.UriSource; + } + + bitmapIcon.ShowAsMonochrome = bitmapIconSource.ShowAsMonochrome; + var newForeground = bitmapIconSource.Foreground; + if (newForeground != null) + { + bitmapIcon.Foreground = newForeground; + } + return bitmapIcon; + } + else if (iconSource is PathIconSource pathIconSource) + { + PathIcon pathIcon = new PathIcon(); + + if (pathIconSource.Data != null) + { + pathIcon.Data = pathIconSource.Data; + } + var newForeground = pathIconSource.Foreground; + if (newForeground != null) + { + pathIcon.Foreground = newForeground; + } + return pathIcon; + } + return null; + } + + /// + /// Applies selected background effect to when is rendered. + /// + /// Window to apply effect. + /// Skip the compatibility check. + public static bool TryApplyMica(Window window, bool force = false) + { + if (!force && !(OSVersionHelper.OSVersion >= new Version(10, 0, 21996))) { return false; } + + window.WindowStyle = WindowStyle.SingleBorderWindow; + + var windowHandle = new WindowInteropHelper(window).EnsureHandle(); + + if (windowHandle == IntPtr.Zero) { return false; } + + return TryApplyMica(windowHandle); + } + + private static bool TryApplyMica(IntPtr handle) + { + int backdropPvAttribute; + + if (OSVersionHelper.OSVersion >= new Version(10, 0, 22523)) + { + backdropPvAttribute = (int)DWMAPI.DWMSBT.DWMSBT_MAINWINDOW; + + DWMAPI.DwmSetWindowAttribute(handle, DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, + ref backdropPvAttribute, + Marshal.SizeOf(typeof(int))); + + return true; + } + + if (!RemoveTitleBar(handle)) { return false; } + + backdropPvAttribute = (int)DWMAPI.PvAttribute.Enable; + + DWMAPI.DwmSetWindowAttribute(handle, DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_MICA_EFFECT, + ref backdropPvAttribute, + Marshal.SizeOf(typeof(int))); + + return true; + } + + /// + /// Tries to remove background effects if they have been applied to the . + /// + /// The window from which the effect should be removed. + public static void RemoveMica(Window window) + { + window.WindowStyle = WindowStyle.None; + + var windowHandle = new WindowInteropHelper(window).EnsureHandle(); + + if (windowHandle == IntPtr.Zero) return; + + RemoveMica(windowHandle); + } + + /// + /// Tries to remove all effects if they have been applied to the hWnd. + /// + /// Pointer to the window handle. + public static void RemoveMica(IntPtr handle) + { + if (handle == IntPtr.Zero) return; + + int pvAttribute = (int)DWMAPI.PvAttribute.Disable; + int backdropPvAttribute = (int)DWMAPI.DWMSBT.DWMSBT_DISABLE; + + DWMAPI.DwmSetWindowAttribute(handle, DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_MICA_EFFECT, ref pvAttribute, + Marshal.SizeOf(typeof(int))); + + DWMAPI.DwmSetWindowAttribute(handle, DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, + ref backdropPvAttribute, + Marshal.SizeOf(typeof(int))); + } + + /// + /// Tries to inform the operating system that this window uses dark mode. + /// + /// Window to apply effect. + public static void ApplyDarkMode(this Window window) + { + var windowHandle = new WindowInteropHelper(window).EnsureHandle(); + + if (windowHandle == IntPtr.Zero) return; + + ApplyDarkMode(windowHandle); + } + + /// + /// Tries to inform the operating system that this hWnd uses dark mode. + /// + /// Pointer to the window handle. + public static void ApplyDarkMode(IntPtr handle) + { + if (handle == IntPtr.Zero) return; + + var pvAttribute = (int)DWMAPI.PvAttribute.Enable; + var dwAttribute = DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE; + + if (OSVersionHelper.OSVersion < new Version(10, 0, 18985)) + { + dwAttribute = DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_OLD; + } + + DWMAPI.DwmSetWindowAttribute(handle, dwAttribute, + ref pvAttribute, + Marshal.SizeOf(typeof(int))); + } + + /// + /// Tries to clear the dark theme usage information. + /// + /// Window to remove effect. + public static void RemoveDarkMode(this Window window) + { + var windowHandle = new WindowInteropHelper(window).EnsureHandle(); + + if (windowHandle == IntPtr.Zero) return; + + RemoveDarkMode(windowHandle); + } + + /// + /// Tries to clear the dark theme usage information. + /// + /// Pointer to the window handle. + public static void RemoveDarkMode(IntPtr handle) + { + if (handle == IntPtr.Zero) { return; } + + var pvAttribute = (int)DWMAPI.PvAttribute.Disable; + var dwAttribute = DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE; + + if (OSVersionHelper.OSVersion < new Version(10, 0, 18985)) + { + dwAttribute = DWMAPI.DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_OLD; + } + + DWMAPI.DwmSetWindowAttribute(handle, dwAttribute, + ref pvAttribute, + Marshal.SizeOf(typeof(int))); + } + + /// + /// Tries to remove default TitleBar from hWnd. + /// + /// Window to remove effect. + public static void RemoveTitleBar(this Window window) + { + var windowHandle = new WindowInteropHelper(window).EnsureHandle(); + + if (windowHandle == IntPtr.Zero) return; + + RemoveTitleBar(windowHandle); + } + + /// + /// Tries to remove default TitleBar from hWnd. + /// + /// Pointer to the window handle. + /// is problem occurs. + private static bool RemoveTitleBar(IntPtr handle) + { + // Hide default TitleBar + // https://stackoverflow.com/questions/743906/how-to-hide-close-button-in-wpf-window + try + { + SetWindowLong(handle, -16, GetWindowLong(handle, -16) & ~0x80000); + + return true; + } + catch (Exception e) + { +#if DEBUG + Console.WriteLine(e); +#endif + return false; + } + } + + /// + /// Retrieves information about the specified window. + /// The function also retrieves the 32-bit (DWORD) value at the specified offset into the extra window memory. + /// + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + /// + /// Changes an attribute of the specified window. + /// The function also sets the 32-bit (long) value at the specified offset into the extra window memory. + /// + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + } +} diff --git a/ModernWpf.MessageBox/LocalizedDialogCommands.cs b/ModernWpf.MessageBox/LocalizedDialogCommands.cs index bd9c3a0..7104925 100644 --- a/ModernWpf.MessageBox/LocalizedDialogCommands.cs +++ b/ModernWpf.MessageBox/LocalizedDialogCommands.cs @@ -1,9 +1,12 @@ using System; using System.Runtime.InteropServices; -namespace ModernWpf { - internal static class LocalizedDialogCommands { - public static string GetString(DialogBoxCommand command) { +namespace ModernWpf +{ + internal static class LocalizedDialogCommands + { + public static string GetString(DialogBoxCommand command) + { return Marshal.PtrToStringAuto(MB_GetString((int)command))?.TrimStart('&')!; } @@ -18,7 +21,8 @@ public static string GetString(DialogBoxCommand command) { /// /// Represents possible dialogbox command id values by the MB_GetString function. /// - public enum DialogBoxCommand : int { + public enum DialogBoxCommand : int + { IDOK = 0, IDCANCEL = 1, IDABORT = 2, diff --git a/ModernWpf.MessageBox/MessageBox.cs b/ModernWpf.MessageBox/MessageBox.cs deleted file mode 100644 index 49b45cd..0000000 --- a/ModernWpf.MessageBox/MessageBox.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System.Linq; -using System.Threading.Tasks; -using System.Windows; -using ModernWpf.Controls; -using ModernWpf.Extensions; - -namespace ModernWpf { - public static class MessageBox { - public static bool EnableLocalization { get; set; } = true; - - #region Sync - public static MessageBoxResult? Show(string messageBoxText) => - Show(null, true, messageBoxText, null, null, null, null); - public static MessageBoxResult? Show(string messageBoxText, string? caption) => - Show(null, true, messageBoxText, caption, null, null, null); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button) => - Show(null, true, messageBoxText, caption, button, null, null); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol) => - Show(null, messageBoxText, caption, button, symbol, null); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol) => - Show(null, messageBoxText, caption, button, symbol, null); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image) => - Show(null, messageBoxText, caption, button, image, null); - public static MessageBoxResult Show(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol, MessageBoxResult defaultResult) => - Show(null, messageBoxText, caption, button, symbol, defaultResult); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol, MessageBoxResult? defaultResult) => - Show(null, messageBoxText, caption, button, symbol, defaultResult); - public static MessageBoxResult Show(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol, MessageBoxResult defaultResult) => - Show(null, messageBoxText, caption, button, symbol, defaultResult); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol, MessageBoxResult? defaultResult) => - Show(null, messageBoxText, caption, button, symbol, defaultResult); - public static MessageBoxResult Show(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image, MessageBoxResult defaultResult) => - Show(null, messageBoxText, caption, button, image, defaultResult); - public static MessageBoxResult? Show(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image, MessageBoxResult? defaultResult) => - Show(null, messageBoxText, caption, button, image, defaultResult); - public static MessageBoxResult? Show(Window? owner, string messageBoxText) => - Show(owner, false, messageBoxText, null, null, null, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption) => - Show(owner, false, messageBoxText, caption, null, null, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button) => - Show(owner, false, messageBoxText, caption, button, null, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol) => - Show(owner, messageBoxText, caption, button, symbol, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol) => - Show(owner, messageBoxText, caption, button, symbol, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image) => - Show(owner, messageBoxText, caption, button, image, null); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph) => - Show(owner, false, messageBoxText, caption, button, glyph, null); - public static MessageBoxResult Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol, MessageBoxResult defaultResult) => - Show(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol, MessageBoxResult? defaultResult) => - Show(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static MessageBoxResult Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol, MessageBoxResult defaultResult) => - Show(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol, MessageBoxResult? defaultResult) => - Show(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static MessageBoxResult Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image, MessageBoxResult defaultResult) => - Show(owner, messageBoxText, caption, button, image.ToSymbol(), defaultResult); - public static MessageBoxResult? Show(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image, MessageBoxResult? defaultResult) => - Show(owner, messageBoxText, caption, button, image.ToSymbol(), defaultResult); - - public static MessageBoxResult Show(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult defaultResult) => - ShowInternal(owner, lookForOwner, messageBoxText, caption, button, glyph, defaultResult) ?? defaultResult; - - public static MessageBoxResult? Show(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult? defaultResult) => - ShowInternal(owner, lookForOwner, messageBoxText, caption, button, glyph, defaultResult); - -#if !NET45 && !NET462 - [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("defaultResult")] -#endif - private static MessageBoxResult? ShowInternal(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult? defaultResult) { - if (owner is null && lookForOwner) - owner = GetActiveWindow(); - - var window = new MessageBoxWindow(messageBoxText, caption ?? string.Empty, button ?? MessageBoxButton.OK, glyph) { - Owner = owner, - WindowStartupLocation = owner is null ? WindowStartupLocation.CenterScreen : WindowStartupLocation.CenterOwner - }; - window.ShowDialog(); - - return window.Result ?? defaultResult; - } - #endregion Sync - - #region Async - public static Task ShowAsync(string messageBoxText) => - ShowAsync(null, true, messageBoxText, null, null, null, null); - public static Task ShowAsync(string messageBoxText, string? caption) => - ShowAsync(null, true, messageBoxText, caption, null, null, null); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button) => - ShowAsync(null, true, messageBoxText, caption, button, null, null); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol) => - ShowAsync(null, messageBoxText, caption, button, symbol, null); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol) => - ShowAsync(null, messageBoxText, caption, button, symbol, null); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image) => - ShowAsync(null, messageBoxText, caption, button, image, null); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol, MessageBoxResult defaultResult) => - ShowAsync(null, messageBoxText, caption, button, symbol, defaultResult); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, Symbol symbol, MessageBoxResult? defaultResult) => - ShowAsync(null, messageBoxText, caption, button, symbol, defaultResult); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol, MessageBoxResult defaultResult) => - ShowAsync(null, messageBoxText, caption, button, symbol, defaultResult); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, SymbolGlyph symbol, MessageBoxResult? defaultResult) => - ShowAsync(null, messageBoxText, caption, button, symbol, defaultResult); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image, MessageBoxResult defaultResult) => - ShowAsync(null, messageBoxText, caption, button, image, defaultResult); - public static Task ShowAsync(string messageBoxText, string? caption, MessageBoxButton button, MessageBoxImage image, MessageBoxResult? defaultResult) => - ShowAsync(null, messageBoxText, caption, button, image, defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText) => - ShowAsync(owner, false, messageBoxText, null, null, null, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption) => - ShowAsync(owner, false, messageBoxText, caption, null, null, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button) => - ShowAsync(owner, false, messageBoxText, caption, button, null, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol) => - ShowAsync(owner, messageBoxText, caption, button, symbol, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol) => - ShowAsync(owner, messageBoxText, caption, button, symbol, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image) => - ShowAsync(owner, messageBoxText, caption, button, image, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph) => - ShowAsync(owner, false, messageBoxText, caption, button, glyph, null); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol, MessageBoxResult defaultResult) => - ShowAsync(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, Symbol symbol, MessageBoxResult? defaultResult) => - ShowAsync(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol, MessageBoxResult defaultResult) => - ShowAsync(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, SymbolGlyph symbol, MessageBoxResult? defaultResult) => - ShowAsync(owner, false, messageBoxText, caption, button, symbol.ToGlyph(), defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image, MessageBoxResult defaultResult) => - ShowAsync(owner, messageBoxText, caption, button, image.ToSymbol(), defaultResult); - public static Task ShowAsync(Window? owner, string messageBoxText, string? caption, MessageBoxButton? button, MessageBoxImage image, MessageBoxResult? defaultResult) => - ShowAsync(owner, messageBoxText, caption, button, image.ToSymbol(), defaultResult); - public static async Task ShowAsync(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult defaultResult) => - (await ShowAsyncInternal(owner, lookForOwner, messageBoxText, caption, button, glyph, defaultResult)).Value; - public static Task ShowAsync(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult? defaultResult) => - ShowAsyncInternal(owner, lookForOwner, messageBoxText, caption, button, glyph, defaultResult); - -#if !NET45 && !NET462 - [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("defaultResult")] -#endif - private static Task ShowAsyncInternal(Window? owner, bool lookForOwner, string messageBoxText, string? caption, MessageBoxButton? button, string? glyph, MessageBoxResult? defaultResult) { - var taskSource = new TaskCompletionSource( -#if !NET45 - TaskCreationOptions.RunContinuationsAsynchronously -#endif - ); - - Application.Current.Dispatcher.Invoke(() => { - var result = ShowInternal(owner, lookForOwner, messageBoxText, caption, button, glyph, defaultResult); - taskSource.TrySetResult(result); - }); - - return taskSource.Task; - } -#endregion Async - - private static Window? GetActiveWindow() => - Application.Current.Windows.Cast() - .FirstOrDefault(window => window.IsActive && window.ShowActivated); - } -} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBox.Helper.cs b/ModernWpf.MessageBox/MessageBox/MessageBox.Helper.cs new file mode 100644 index 0000000..6115983 --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBox.Helper.cs @@ -0,0 +1,600 @@ +using ModernWpf.Controls; +using ModernWpf.Extensions; +using System; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace ModernWpf.Controls +{ + public partial class MessageBox + { + public static bool EnableLocalization { get; set; } = true; + + #region Sync + + /// + /// Displays a message box that has a message and that returns a result. + /// + /// A that specifies the text to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText) => + Show(messageBoxText, null); + + /// + /// Displays a message box that has a message and title bar caption; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption) => + Show(GetActiveWindow(), messageBoxText, caption); + + /// + /// Displays a message box in front of the specified window. The message box displays a message and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText) => + Show(owner, messageBoxText, null); + + /// + /// Displays a message box that has a message, title bar caption, and button; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button) => + Show(GetActiveWindow(), messageBoxText, caption, button); + + /// + /// Displays a message box in front of the specified window. The message box displays a message and title bar caption; and it returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption) => + Show(owner, messageBoxText, caption, MessageBoxButton.OK); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)=> + Show(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon) => + Show(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, string icon) => + Show(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, IconSource icon) => + Show(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, and button; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button) => + Show(owner, messageBoxText, caption, button, (IconSource)null); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)=> + Show(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon, MessageBoxResult defaultResult) => + Show(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, string icon, MessageBoxResult defaultResult) => + Show(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// Use an overload of the Show method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, IconSource icon, MessageBoxResult defaultResult) => + Show(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)=> + Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon) => + Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, string icon) => + Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, IconSource icon) => + Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) => + Show(owner, messageBoxText, caption, button, icon.ToSymbol(), defaultResult); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon, MessageBoxResult defaultResult) => + Show(owner, messageBoxText, caption, button, icon.ToGlyph(), defaultResult); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, string icon, MessageBoxResult defaultResult) => + Show(owner, messageBoxText, caption, button, new FontIconSource { Glyph = icon, FontSize = 30 }, defaultResult); + + /// + /// Displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// A value that specifies which message box button is clicked by the user. + /// By default, the message box appears in front of the window that is currently active. + public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, IconSource icon, MessageBoxResult defaultResult) + { + if (owner is null) + { + owner = GetActiveWindow(); + } + + Controls.MessageBox window = new Controls.MessageBox + { + Owner = owner, + IconSource = icon, + Result = defaultResult, + Content = messageBoxText, + MessageBoxButtons = button, + Caption = caption ?? string.Empty, + WindowStartupLocation = owner is null ? WindowStartupLocation.CenterScreen : WindowStartupLocation.CenterOwner + }; + + return window.ShowDialog(); + } + + #endregion Sync + + #region Async + + /// + /// Begins an asynchronous operation to displays a message box that has a message and that returns a result. + /// + /// A that specifies the text to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText) => + ShowAsync(messageBoxText, null); + + /// + /// Begins an asynchronous operation to displays a message box that has a message and title bar caption; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption) => + ShowAsync(GetActiveWindow(), messageBoxText, caption); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText) => + ShowAsync(owner, messageBoxText, null); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, and button; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button) => + ShowAsync(GetActiveWindow(), messageBoxText, caption, button); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message and title bar caption; and it returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption) => + ShowAsync(owner, messageBoxText, caption, MessageBoxButton.OK); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) => + ShowAsync(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon) => + ShowAsync(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, string icon) => + ShowAsync(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, IconSource icon) => + ShowAsync(messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, and button; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button) => + ShowAsync(owner, messageBoxText, caption, button, (IconSource)null); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) => + ShowAsync(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon, MessageBoxResult defaultResult) => + ShowAsync(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, string icon, MessageBoxResult defaultResult) => + ShowAsync(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box that has a message, title bar caption, button, and icon; and that accepts a default message box result and returns a result. + /// + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// Use an overload of the ShowAsync method, which enables you to specify an owner window. Otherwise, the message box is owned by the window that is currently active. + public static Task ShowAsync(string messageBoxText, string caption, MessageBoxButton button, IconSource icon, MessageBoxResult defaultResult) => + ShowAsync(GetActiveWindow(), messageBoxText, caption, button, icon, defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) => + ShowAsync(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon) => + ShowAsync(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, string icon) => + ShowAsync(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and it also returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, IconSource icon) => + ShowAsync(owner, messageBoxText, caption, button, icon, MessageBoxResult.None); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) => + ShowAsync(owner, messageBoxText, caption, button, icon.ToSymbol(), defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, SymbolGlyph icon, MessageBoxResult defaultResult) => + ShowAsync(owner, messageBoxText, caption, button, icon.ToGlyph(), defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, string icon, MessageBoxResult defaultResult) => + ShowAsync(owner, messageBoxText, caption, button, new FontIconSource { Glyph = icon, FontSize = 30 }, defaultResult); + + /// + /// Begins an asynchronous operation to displays a message box in front of the specified window. The message box displays a message, title bar caption, button, and icon; and accepts a default message box result and returns a result. + /// + /// A that represents the owner window of the message box. + /// A that specifies the text to display. + /// A that specifies the title bar caption to display. + /// A value that specifies which button or buttons to display. + /// A value that specifies the icon to display. + /// A value that specifies the default result of the message box. + /// An asynchronous operation showing the message box. When complete, returns a . + /// By default, the message box appears in front of the window that is currently active. + public static Task ShowAsync(Window owner, string messageBoxText, string caption, MessageBoxButton button, IconSource icon, MessageBoxResult defaultResult) + { + TaskCompletionSource taskSource = new TaskCompletionSource( +#if !NET452 + TaskCreationOptions.RunContinuationsAsynchronously +#endif + ); + + Application.Current.Dispatcher.Invoke(() => + { + MessageBoxResult result = Show(owner, messageBoxText, caption, button, icon, defaultResult); + taskSource.TrySetResult(result); + }); + + return taskSource.Task; + } + + #endregion Async + + private static Window GetActiveWindow() => + Application.Current.Windows.Cast() + .FirstOrDefault(window => window.IsActive && window.ShowActivated); + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBox.cs b/ModernWpf.MessageBox/MessageBox/MessageBox.cs new file mode 100644 index 0000000..2631aff --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBox.cs @@ -0,0 +1,789 @@ +using ModernWpf.Extensions; +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using static ModernWpf.LocalizedDialogCommands; + +namespace ModernWpf.Controls +{ + public partial class MessageBox : Window + { + public MessageBoxResult Result; + + private Button OKButton { get; set; } + private Button YesButton { get; set; } + private Button NoButton { get; set; } + private Button CancelButton { get; set; } + + static MessageBox() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageBox), new FrameworkPropertyMetadata(typeof(MessageBox))); + } + + public MessageBox() + { + SetValue(TemplateSettingsPropertyKey, new MessageBoxTemplateSettings()); + var handler = new RoutedEventHandler((sender, e) => ApplyDarkMode()); + ThemeManager.AddActualThemeChangedHandler(this, handler); + Loaded += On_Loaded; + } + + #region UseMica + + public static readonly DependencyProperty UseMicaProperty = + DependencyProperty.Register( + nameof(UseMica), + typeof(bool), + typeof(MessageBox), + new PropertyMetadata(true, OnUseMicaPropertyChanged)); + + public bool UseMica + { + get => (bool)GetValue(UseMicaProperty); + set => SetValue(UseMicaProperty, value); + } + + #endregion + + #region Caption + + public static readonly DependencyProperty CaptionProperty = + DependencyProperty.Register( + nameof(Caption), + typeof(object), + typeof(MessageBox)); + + public object Caption + { + get => GetValue(CaptionProperty); + set => SetValue(CaptionProperty, value); + } + + #endregion + + #region CaptionTemplate + + public static readonly DependencyProperty CaptionTemplateProperty = + DependencyProperty.Register( + nameof(CaptionTemplate), + typeof(DataTemplate), + typeof(MessageBox)); + + public DataTemplate CaptionTemplate + { + get => (DataTemplate)GetValue(CaptionTemplateProperty); + set => SetValue(CaptionTemplateProperty, value); + } + + #endregion + + #region OKButtonText + + public static readonly DependencyProperty OKButtonTextProperty = + DependencyProperty.Register( + nameof(OKButtonText), + typeof(string), + typeof(MessageBox), + new PropertyMetadata(string.Empty, OnButtonTextChanged)); + + public string OKButtonText + { + get => (string)GetValue(OKButtonTextProperty); + set => SetValue(OKButtonTextProperty, value); + } + + #endregion + + #region OKButtonCommand + + public static readonly DependencyProperty OKButtonCommandProperty = + DependencyProperty.Register( + nameof(OKButtonCommand), + typeof(ICommand), + typeof(MessageBox), + null); + + public ICommand OKButtonCommand + { + get => (ICommand)GetValue(OKButtonCommandProperty); + set => SetValue(OKButtonCommandProperty, value); + } + + #endregion + + #region OKButtonCommandParameter + + public static readonly DependencyProperty OKButtonCommandParameterProperty = + DependencyProperty.Register( + nameof(OKButtonCommandParameter), + typeof(object), + typeof(MessageBox), + null); + + public object OKButtonCommandParameter + { + get => GetValue(OKButtonCommandParameterProperty); + set => SetValue(OKButtonCommandParameterProperty, value); + } + + #endregion + + #region OKButtonStyle + + public static readonly DependencyProperty OKButtonStyleProperty = + DependencyProperty.Register( + nameof(OKButtonStyle), + typeof(Style), + typeof(MessageBox), + null); + + public Style OKButtonStyle + { + get => (Style)GetValue(OKButtonStyleProperty); + set => SetValue(OKButtonStyleProperty, value); + } + + #endregion + + #region YesButtonText + + public static readonly DependencyProperty YesButtonTextProperty = + DependencyProperty.Register( + nameof(YesButtonText), + typeof(string), + typeof(MessageBox), + new PropertyMetadata(string.Empty, OnButtonTextChanged)); + + public string YesButtonText + { + get => (string)GetValue(YesButtonTextProperty); + set => SetValue(YesButtonTextProperty, value); + } + + #endregion + + #region YesButtonCommand + + public static readonly DependencyProperty YesButtonCommandProperty = + DependencyProperty.Register( + nameof(YesButtonCommand), + typeof(ICommand), + typeof(MessageBox), + null); + + public ICommand YesButtonCommand + { + get => (ICommand)GetValue(YesButtonCommandProperty); + set => SetValue(YesButtonCommandProperty, value); + } + + #endregion + + #region YesButtonCommandParameter + + public static readonly DependencyProperty YesButtonCommandParameterProperty = + DependencyProperty.Register( + nameof(YesButtonCommandParameter), + typeof(object), + typeof(MessageBox), + null); + + public object YesButtonCommandParameter + { + get => GetValue(YesButtonCommandParameterProperty); + set => SetValue(YesButtonCommandParameterProperty, value); + } + + #endregion + + #region YesButtonStyle + + public static readonly DependencyProperty YesButtonStyleProperty = + DependencyProperty.Register( + nameof(YesButtonStyle), + typeof(Style), + typeof(MessageBox), + null); + + public Style YesButtonStyle + { + get => (Style)GetValue(YesButtonStyleProperty); + set => SetValue(YesButtonStyleProperty, value); + } + + #endregion + + #region NoButtonText + + public static readonly DependencyProperty NoButtonTextProperty = + DependencyProperty.Register( + nameof(NoButtonText), + typeof(string), + typeof(MessageBox), + new PropertyMetadata(string.Empty, OnButtonTextChanged)); + + public string NoButtonText + { + get => (string)GetValue(NoButtonTextProperty); + set => SetValue(NoButtonTextProperty, value); + } + + #endregion + + #region NoButtonCommand + + public static readonly DependencyProperty NoButtonCommandProperty = + DependencyProperty.Register( + nameof(NoButtonCommand), + typeof(ICommand), + typeof(MessageBox), + null); + + public ICommand NoButtonCommand + { + get => (ICommand)GetValue(NoButtonCommandProperty); + set => SetValue(NoButtonCommandProperty, value); + } + + #endregion + + #region NoButtonCommandParameter + + public static readonly DependencyProperty NoButtonCommandParameterProperty = + DependencyProperty.Register( + nameof(NoButtonCommandParameter), + typeof(object), + typeof(MessageBox), + null); + + public object NoButtonCommandParameter + { + get => GetValue(NoButtonCommandParameterProperty); + set => SetValue(NoButtonCommandParameterProperty, value); + } + + #endregion + + #region NoButtonStyle + + public static readonly DependencyProperty NoButtonStyleProperty = + DependencyProperty.Register( + nameof(NoButtonStyle), + typeof(Style), + typeof(MessageBox), + null); + + public Style NoButtonStyle + { + get => (Style)GetValue(NoButtonStyleProperty); + set => SetValue(NoButtonStyleProperty, value); + } + + #endregion + + #region CancelButtonText + + public static readonly DependencyProperty CancelButtonTextProperty = + DependencyProperty.Register( + nameof(CancelButtonText), + typeof(string), + typeof(MessageBox), + new PropertyMetadata(string.Empty, OnButtonTextChanged)); + + public string CancelButtonText + { + get => (string)GetValue(CancelButtonTextProperty); + set => SetValue(CancelButtonTextProperty, value); + } + + #endregion + + #region CancelButtonCommand + + public static readonly DependencyProperty CancelButtonCommandProperty = + DependencyProperty.Register( + nameof(CancelButtonCommand), + typeof(ICommand), + typeof(MessageBox), + null); + + public ICommand CancelButtonCommand + { + get => (ICommand)GetValue(CancelButtonCommandProperty); + set => SetValue(CancelButtonCommandProperty, value); + } + + #endregion + + #region CancelButtonCommandParameter + + public static readonly DependencyProperty CancelButtonCommandParameterProperty = + DependencyProperty.Register( + nameof(CancelButtonCommandParameter), + typeof(object), + typeof(MessageBox), + null); + + public object CancelButtonCommandParameter + { + get => GetValue(CancelButtonCommandParameterProperty); + set => SetValue(CancelButtonCommandParameterProperty, value); + } + + #endregion + + #region CancelButtonStyle + + public static readonly DependencyProperty CancelButtonStyleProperty = + DependencyProperty.Register( + nameof(CancelButtonStyle), + typeof(Style), + typeof(MessageBox), + null); + + public Style CancelButtonStyle + { + get => (Style)GetValue(CancelButtonStyleProperty); + set => SetValue(CancelButtonStyleProperty, value); + } + + #endregion + + #region CornerRadius + + public static readonly DependencyProperty CornerRadiusProperty = + DependencyProperty.Register( + nameof(CornerRadius), + typeof(CornerRadius), + typeof(MessageBox)); + + public CornerRadius CornerRadius + { + get => (CornerRadius)GetValue(CornerRadiusProperty); + set => SetValue(CornerRadiusProperty, value); + } + + #endregion + + #region IconSource + + public IconSource IconSource + { + get => (IconSource)GetValue(IconSourceProperty); + set => SetValue(IconSourceProperty, value); + } + + public static readonly DependencyProperty IconSourceProperty = + DependencyProperty.Register( + nameof(IconSource), + typeof(IconSource), + typeof(MessageBox), + new PropertyMetadata(OnIconSourcePropertyChanged)); + + private static void OnIconSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + ((MessageBox)sender).OnIconSourcePropertyChanged(args); + } + + #endregion + + #region MessageBoxButtons + + public MessageBoxButton MessageBoxButtons + { + get => (MessageBoxButton)GetValue(MessageBoxButtonsProperty); + set => SetValue(MessageBoxButtonsProperty, value); + } + + public static readonly DependencyProperty MessageBoxButtonsProperty = + DependencyProperty.Register( + nameof(MessageBoxButtons), + typeof(MessageBoxButton), + typeof(MessageBox), + new PropertyMetadata(OnMessageBoxButtonsPropertyChanged)); + + private static void OnMessageBoxButtonsPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) + { + ((MessageBox)sender).UpdateMessageBoxButtonState(); + } + + #endregion + + #region DefaultResult + + public MessageBoxResult DefaultResult + { + get => (MessageBoxResult)GetValue(DefaultResultProperty); + set => SetValue(DefaultResultProperty, value); + } + + public static readonly DependencyProperty DefaultResultProperty = + DependencyProperty.Register( + nameof(DefaultResult), + typeof(MessageBoxResult), + typeof(MessageBox)); + + #endregion + + #region TemplateSettings + + private static readonly DependencyPropertyKey TemplateSettingsPropertyKey = + DependencyProperty.RegisterReadOnly( + nameof(TemplateSettings), + typeof(MessageBoxTemplateSettings), + typeof(MessageBox), + null); + + public static readonly DependencyProperty TemplateSettingsProperty = + TemplateSettingsPropertyKey.DependencyProperty; + + public MessageBoxTemplateSettings TemplateSettings + { + get => (MessageBoxTemplateSettings)GetValue(TemplateSettingsProperty); + } + + #endregion + + public event TypedEventHandler Opened; + + public event TypedEventHandler Closing; + + public event TypedEventHandler Closed; + + public event TypedEventHandler OKButtonClick; + + public event TypedEventHandler YesButtonClick; + + public event TypedEventHandler NoButtonClick; + + public event TypedEventHandler CancelButtonClick; + + private static void OnButtonTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MessageBox)d).UpdateButtonTextState(); + } + + private static void OnUseMicaPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MessageBox)d).UpdateMica(); + } + + void OnIconSourcePropertyChanged(DependencyPropertyChangedEventArgs args) + { + if (args.NewValue is IconSource iconSource) + { + TemplateSettings.IconElement = iconSource.MakeIconElementFrom(); + } + else + { + TemplateSettings.ClearValue(MessageBoxTemplateSettings.IconElementProperty); + } + UpdateIconState(); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (OKButton != null) + { + OKButton.Click -= OnButtonClick; + } + + if (YesButton != null) + { + YesButton.Click -= OnButtonClick; + } + + if (NoButton != null) + { + NoButton.Click -= OnButtonClick; + } + + if (CancelButton != null) + { + CancelButton.Click -= OnButtonClick; + } + + OKButton = GetTemplateChild(nameof(OKButton)) as Button; + YesButton = GetTemplateChild(nameof(YesButton)) as Button; + NoButton = GetTemplateChild(nameof(NoButton)) as Button; + CancelButton = GetTemplateChild(nameof(CancelButton)) as Button; + + if (OKButton != null) + { + OKButton.Click += OnButtonClick; + } + + if (YesButton != null) + { + YesButton.Click += OnButtonClick; + } + + if (NoButton != null) + { + NoButton.Click += OnButtonClick; + } + + if (CancelButton != null) + { + CancelButton.Click += OnButtonClick; + CancelButton.IsCancel = true; + } + + UpdateIconState(); + UpdateMessageState(); + UpdateButtonTextState(); + UpdateMessageBoxButtonState(); + } + + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + + InvalidateMeasure(); + } + + private void OnButtonClick(object sender, RoutedEventArgs e) + { + if (sender == OKButton) + { + HandleButtonClick( + OKButtonClick, + OKButtonCommand, + OKButtonCommandParameter, + MessageBoxResult.OK); + } + else if (sender == YesButton) + { + HandleButtonClick( + YesButtonClick, + YesButtonCommand, + YesButtonCommandParameter, + MessageBoxResult.Yes); + } + else if (sender == NoButton) + { + HandleButtonClick( + NoButtonClick, + NoButtonCommand, + NoButtonCommandParameter, + MessageBoxResult.No); + } + else if (sender == CancelButton) + { + HandleButtonClick( + CancelButtonClick, + CancelButtonCommand, + CancelButtonCommandParameter, + MessageBoxResult.Cancel); + } + } + + private void HandleButtonClick( + TypedEventHandler handler, + ICommand command, + object commandParameter, + MessageBoxResult result) + { + if (handler != null) + { + var args = new MessageBoxButtonClickEventArgs(); + + var deferral = new MessageBoxButtonClickDeferral(() => + { + if (!args.Cancel) + { + TryExecuteCommand(command, commandParameter); + Close(result); + } + }); + + args.SetDeferral(deferral); + + args.IncrementDeferralCount(); + handler(this, args); + args.DecrementDeferralCount(); + } + else + { + TryExecuteCommand(command, commandParameter); + Close(result); + } + } + + private void UpdateButtonTextState() + { + var templateSettings = TemplateSettings; + templateSettings.OKButtonText = string.IsNullOrEmpty(OKButtonText) ? GetString(DialogBoxCommand.IDOK) : OKButtonText; + templateSettings.YesButtonText = string.IsNullOrEmpty(YesButtonText) ? GetString(DialogBoxCommand.IDYES) : YesButtonText; + templateSettings.NoButtonText = string.IsNullOrEmpty(NoButtonText) ? GetString(DialogBoxCommand.IDNO) : NoButtonText; + templateSettings.CancelButtonText = string.IsNullOrEmpty(CancelButtonText) ? GetString(DialogBoxCommand.IDCANCEL) : CancelButtonText; + } + + private void UpdateMessageState() + { + string stateName = Caption == null || (Caption is string && string.IsNullOrEmpty((string)Caption)) ? TitleCollapsedState : TitleVisibleState; + VisualStateManager.GoToState(this, stateName, true); + } + + private void UpdateIconState() + { + string stateName = TemplateSettings.IconElement == null ? IconCollapsedState : IconVisibleState; + VisualStateManager.GoToState(this, stateName, true); + } + + private void UpdateMessageBoxButtonState() + { + string stateName; + + MessageBoxButton button = MessageBoxButtons; + + switch (button) + { + case MessageBoxButton.OK: + stateName = OKVisibleState; + if (OKButton != null) { OKButton.Focus(); } + break; + case MessageBoxButton.OKCancel: + stateName = OKCancelVisibleState; + if (OKButton != null) { OKButton.Focus(); } + break; + case MessageBoxButton.YesNoCancel: + stateName = YesNoCancelVisibleState; + if (YesButton != null) { YesButton.Focus(); } + break; + case MessageBoxButton.YesNo: + stateName = YesNoVisibleState; + if (YesButton != null) { YesButton.Focus(); } + break; + default: + stateName = OKVisibleState; + if (OKButton != null) { OKButton.Focus(); } + break; + } + + VisualStateManager.GoToState(this, stateName, true); + + switch (button) + { + case MessageBoxButton.OK: + stateName = OKAsDefaultButtonState; + break; + case MessageBoxButton.OKCancel: + stateName = OKAsDefaultButtonState; + break; + case MessageBoxButton.YesNoCancel: + stateName = YesAsDefaultButtonState; + break; + case MessageBoxButton.YesNo: + stateName = YesAsDefaultButtonState; + break; + default: + stateName = OKAsDefaultButtonState; + break; + } + + VisualStateManager.GoToState(this, stateName, true); + } + + /// + /// Opens a Message Box and returns only when the newly opened window is closed. + /// + /// A value that specifies which message box button is clicked by the user. + public new MessageBoxResult ShowDialog() + { + base.ShowDialog(); + return Result; + } + + public void Close(MessageBoxResult result) + { + var closing = Closing; + if (closing != null) + { + var args = new MessageBoxClosingEventArgs(result); + + var deferral = new MessageBoxClosingDeferral(() => + { + if (!args.Cancel) + { + Result = result; + Close(); + Closed?.Invoke(this, new MessageBoxClosedEventArgs(result)); + } + }); + + args.SetDeferral(deferral); + + args.IncrementDeferralCount(); + closing(this, args); + args.DecrementDeferralCount(); + } + else + { + Result = result; + Close(); + Closed?.Invoke(this, new MessageBoxClosedEventArgs(result)); + } + } + + private void On_Loaded(object sender, RoutedEventArgs e) + { + UpdateMica(); + ApplyDarkMode(); + this.RemoveTitleBar(); + Opened?.Invoke(this, new MessageBoxOpenedEventArgs()); + } + + private static void TryExecuteCommand(ICommand command, object parameter) + { + if (command != null && command.CanExecute(parameter)) + { + command.Execute(parameter); + } + } + + private void UpdateMica() + { + if (UseMica) { UIExtensions.TryApplyMica(this); } + else { UIExtensions.RemoveMica(this); } + } + + private void ApplyDarkMode() + { + var theme = ThemeManager.GetActualTheme(this); + + bool IsDark(ElementTheme theme) + { + return theme == ElementTheme.Default + ? ThemeManager.Current.ActualApplicationTheme == ApplicationTheme.Dark + : theme == ElementTheme.Dark; + } + + if (IsDark(theme)) + { + UIExtensions.ApplyDarkMode(this); + } + else + { + this.RemoveDarkMode(); + } + } + + private const string OKVisibleState = "OKVisible"; + private const string OKCancelVisibleState = "OKCancelVisible"; + private const string YesNoCancelVisibleState = "YesNoCancelVisible"; + private const string YesNoVisibleState = "YesNoVisible"; + + private const string OKAsDefaultButtonState = "OKAsDefaultButton"; + private const string YesAsDefaultButtonState = "YesAsDefaultButton"; + + private const string IconVisibleState = "IconVisible"; + private const string IconCollapsedState = "IconCollapsed"; + + private const string TitleVisibleState = "TitleVisible"; + private const string TitleCollapsedState = "TitleCollapsed"; + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBox.xaml b/ModernWpf.MessageBox/MessageBox/MessageBox.xaml new file mode 100644 index 0000000..ca95f2e --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBox.xaml @@ -0,0 +1,297 @@ + + + + + + + + 320 + 548 + 184 + 756 + 8 + 0,0,0,12 + 24 + + + + + + \ No newline at end of file diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickDeferral.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickDeferral.cs new file mode 100644 index 0000000..7a7d66b --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickDeferral.cs @@ -0,0 +1,19 @@ +using System; + +namespace ModernWpf.Controls +{ + public sealed class MessageBoxButtonClickDeferral + { + private readonly Action _handler; + + internal MessageBoxButtonClickDeferral(Action handler) + { + _handler = handler ?? throw new ArgumentNullException(nameof(handler)); + } + + public void Complete() + { + _handler(); + } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickEventArgs.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickEventArgs.cs new file mode 100644 index 0000000..4af177c --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxButtonClickEventArgs.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; + +namespace ModernWpf.Controls +{ + public class MessageBoxButtonClickEventArgs : EventArgs + { + private MessageBoxButtonClickDeferral _deferral; + private int _deferralCount; + + internal MessageBoxButtonClickEventArgs() + { + } + + public bool Cancel { get; set; } + + public MessageBoxButtonClickDeferral GetDeferral() + { + _deferralCount++; + + return new MessageBoxButtonClickDeferral(() => + { + DecrementDeferralCount(); + }); + } + + internal void SetDeferral(MessageBoxButtonClickDeferral deferral) + { + _deferral = deferral; + } + + internal void DecrementDeferralCount() + { + Debug.Assert(_deferralCount > 0); + _deferralCount--; + if (_deferralCount == 0) + { + _deferral.Complete(); + } + } + + internal void IncrementDeferralCount() + { + _deferralCount++; + } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxClosedEventArgs.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxClosedEventArgs.cs new file mode 100644 index 0000000..cc9bf74 --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxClosedEventArgs.cs @@ -0,0 +1,15 @@ +using System; +using System.Windows; + +namespace ModernWpf.Controls +{ + public class MessageBoxClosedEventArgs : EventArgs + { + internal MessageBoxClosedEventArgs(MessageBoxResult result) + { + Result = result; + } + + public MessageBoxResult Result { get; } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxClosingDeferral.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxClosingDeferral.cs new file mode 100644 index 0000000..326bd32 --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxClosingDeferral.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModernWpf.Controls +{ + public sealed class MessageBoxClosingDeferral + { + private readonly Action _handler; + + internal MessageBoxClosingDeferral(Action handler) + { + _handler = handler ?? throw new ArgumentNullException(nameof(handler)); + } + + public void Complete() + { + _handler(); + } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxClosingEventArgs.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxClosingEventArgs.cs new file mode 100644 index 0000000..51be654 --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxClosingEventArgs.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; +using System.Windows; + +namespace ModernWpf.Controls +{ + public sealed class MessageBoxClosingEventArgs : EventArgs + { + private MessageBoxClosingDeferral _deferral; + private int _deferralCount; + + internal MessageBoxClosingEventArgs(MessageBoxResult result) + { + Result = result; + } + + public bool Cancel { get; set; } + + public MessageBoxResult Result { get; } + + public MessageBoxClosingDeferral GetDeferral() + { + _deferralCount++; + + return new MessageBoxClosingDeferral(() => + { + DecrementDeferralCount(); + }); + } + + internal void SetDeferral(MessageBoxClosingDeferral deferral) + { + _deferral = deferral; + } + + internal void DecrementDeferralCount() + { + Debug.Assert(_deferralCount > 0); + _deferralCount--; + if (_deferralCount == 0) + { + _deferral.Complete(); + } + } + + internal void IncrementDeferralCount() + { + _deferralCount++; + } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxOpenedEventArgs.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxOpenedEventArgs.cs new file mode 100644 index 0000000..eeff1ab --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxOpenedEventArgs.cs @@ -0,0 +1,11 @@ +using System; + +namespace ModernWpf.Controls +{ + public class MessageBoxOpenedEventArgs : EventArgs + { + internal MessageBoxOpenedEventArgs() + { + } + } +} diff --git a/ModernWpf.MessageBox/MessageBox/MessageBoxTemplateSettings.cs b/ModernWpf.MessageBox/MessageBox/MessageBoxTemplateSettings.cs new file mode 100644 index 0000000..d363956 --- /dev/null +++ b/ModernWpf.MessageBox/MessageBox/MessageBoxTemplateSettings.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using ModernWpf.Controls.Primitives; +using static ModernWpf.LocalizedDialogCommands; + +namespace ModernWpf.Controls +{ + public class MessageBoxTemplateSettings : DependencyObject + { + internal MessageBoxTemplateSettings() + { + } + + #region IconElement + + private static readonly DependencyPropertyKey IconElementPropertyKey = + DependencyProperty.RegisterReadOnly( + nameof(IconElement), + typeof(IconElement), + typeof(MessageBoxTemplateSettings), + null); + + public static readonly DependencyProperty IconElementProperty = IconElementPropertyKey.DependencyProperty; + + public IconElement IconElement + { + get => (IconElement)GetValue(IconElementProperty); + internal set => SetValue(IconElementPropertyKey, value); + } + + #endregion + + #region OKButtonText + + public static readonly DependencyProperty OKButtonTextProperty = + DependencyProperty.Register( + nameof(OKButtonText), + typeof(string), + typeof(MessageBoxTemplateSettings), + new PropertyMetadata(GetString(DialogBoxCommand.IDOK))); + + public string OKButtonText + { + get => (string)GetValue(OKButtonTextProperty); + set => SetValue(OKButtonTextProperty, value); + } + + #endregion + + #region YesButtonText + + public static readonly DependencyProperty YesButtonTextProperty = + DependencyProperty.Register( + nameof(YesButtonText), + typeof(string), + typeof(MessageBoxTemplateSettings), + new PropertyMetadata(GetString(DialogBoxCommand.IDYES))); + + public string YesButtonText + { + get => (string)GetValue(YesButtonTextProperty); + set => SetValue(YesButtonTextProperty, value); + } + + #endregion + + #region NoButtonText + + public static readonly DependencyProperty NoButtonTextProperty = + DependencyProperty.Register( + nameof(NoButtonText), + typeof(string), + typeof(MessageBoxTemplateSettings), + new PropertyMetadata(GetString(DialogBoxCommand.IDNO))); + + public string NoButtonText + { + get => (string)GetValue(NoButtonTextProperty); + set => SetValue(NoButtonTextProperty, value); + } + + #endregion + + #region CancelButtonText + + public static readonly DependencyProperty CancelButtonTextProperty = + DependencyProperty.Register( + nameof(CancelButtonText), + typeof(string), + typeof(MessageBoxTemplateSettings), + new PropertyMetadata(GetString(DialogBoxCommand.IDCANCEL))); + + public string CancelButtonText + { + get => (string)GetValue(CancelButtonTextProperty); + set => SetValue(CancelButtonTextProperty, value); + } + + #endregion + } +} diff --git a/ModernWpf.MessageBox/MessageBoxWindow.xaml b/ModernWpf.MessageBox/MessageBoxWindow.xaml deleted file mode 100644 index 8564308..0000000 --- a/ModernWpf.MessageBox/MessageBoxWindow.xaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - -