using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; using MainShell.Common.View; using MainShell.Common.ViewModel; namespace MainShell.Common { public static class MwMessageBoxGlyphs { public const string None = "\uE686"; public const string Information = "\uE625"; public const string Warning = "\uE7BD"; public const string Error = "\uE76C"; public const string Question = "\uE686"; } public sealed class MwMessageBoxButtonText { public string Ok { get; set; } = "确定"; public string Cancel { get; set; } = "取消"; public string Yes { get; set; } = "是"; public string No { get; set; } = "否"; public string Retry { get; set; } = "重试"; public string Abort { get; set; } = "终止"; public string Ignore { get; set; } = "忽略"; public static MwMessageBoxButtonText CreateDefault() { return new MwMessageBoxButtonText(); } } public sealed class MwMessageBoxButtonDefinition { public string Text { get; set; } public MessageBoxResult Result { get; set; } public bool IsDefault { get; set; } public bool IsCancel { get; set; } public bool IsPrimary { get; set; } public Style ButtonStyle { get; set; } } public sealed class MwMessageBoxIconTheme { public string NoneGlyph { get; set; } = MwMessageBoxGlyphs.None; public string InformationGlyph { get; set; } = MwMessageBoxGlyphs.Information; public string WarningGlyph { get; set; } = MwMessageBoxGlyphs.Warning; public string ErrorGlyph { get; set; } = MwMessageBoxGlyphs.Error; public string QuestionGlyph { get; set; } = MwMessageBoxGlyphs.Question; public static MwMessageBoxIconTheme CreateDefault() { return new MwMessageBoxIconTheme(); } } public sealed class MwMessageBoxColorPalette { public MwMessageBoxColorPalette() { } public MwMessageBoxColorPalette(string accentColor, string iconBackgroundColor, string iconForegroundColor) { AccentColor = accentColor; IconBackgroundColor = iconBackgroundColor; IconForegroundColor = iconForegroundColor; } public string AccentColor { get; set; } public string IconBackgroundColor { get; set; } public string IconForegroundColor { get; set; } } public sealed class MwMessageBoxButtonColorTheme { public MwMessageBoxButtonColorTheme() { } public MwMessageBoxButtonColorTheme(string backgroundColor, string hoverBackgroundColor, string pressedBackgroundColor, string borderColor, string foregroundColor) { BackgroundColor = backgroundColor; HoverBackgroundColor = hoverBackgroundColor; PressedBackgroundColor = pressedBackgroundColor; BorderColor = borderColor; ForegroundColor = foregroundColor; } public string BackgroundColor { get; set; } public string HoverBackgroundColor { get; set; } public string PressedBackgroundColor { get; set; } public string BorderColor { get; set; } public string ForegroundColor { get; set; } } public sealed class MwMessageBoxVisualTheme { public MwMessageBoxColorPalette NonePalette { get; set; } = new MwMessageBoxColorPalette("#9CA3AF", "#F3F4F6", "#6B7280"); public MwMessageBoxColorPalette InformationPalette { get; set; } = new MwMessageBoxColorPalette("#38BDF8", "#E0F2FE", "#0284C7"); public MwMessageBoxColorPalette WarningPalette { get; set; } = new MwMessageBoxColorPalette("#F59E0B", "#FEF3C7", "#D97706"); public MwMessageBoxColorPalette ErrorPalette { get; set; } = new MwMessageBoxColorPalette("#EF4444", "#FEE2E2", "#DC2626"); public MwMessageBoxColorPalette QuestionPalette { get; set; } = new MwMessageBoxColorPalette("#3B82F6", "#DBEAFE", "#2563EB"); public MwMessageBoxButtonColorTheme PrimaryButtonTheme { get; set; } = new MwMessageBoxButtonColorTheme("#0E6AE8", "#0B5AD0", "#094BAC", "#0E6AE8", "#FFFFFF"); public MwMessageBoxButtonColorTheme SecondaryButtonTheme { get; set; } = new MwMessageBoxButtonColorTheme("#F3F4F6", "#E5E7EB", "#D1D5DB", "#D1D5DB", "#374151"); public static MwMessageBoxVisualTheme CreateDefault() { return new MwMessageBoxVisualTheme(); } } public sealed class MwMessageBoxState { public string Caption { get; set; } public string Message { get; set; } public string IconGlyph { get; set; } public string IconPathData { get; set; } public string TimeText { get; set; } public Brush AccentBrush { get; set; } public Brush IconBackgroundBrush { get; set; } public Brush IconForegroundBrush { get; set; } public IReadOnlyList Buttons { get; set; } public MessageBoxResult DefaultResult { get; set; } public TextAlignment MessageTextAlignment { get; set; } = TextAlignment.Left; public FlowDirection WindowFlowDirection { get; set; } = FlowDirection.LeftToRight; public FlowDirection MessageFlowDirection { get; set; } = FlowDirection.LeftToRight; } public static class MwMessageBox { public static MwMessageBoxButtonText DefaultButtonText { get; set; } = MwMessageBoxButtonText.CreateDefault(); public static MwMessageBoxIconTheme IconTheme { get; set; } = MwMessageBoxIconTheme.CreateDefault(); public static MwMessageBoxVisualTheme VisualTheme { get; set; } = MwMessageBoxVisualTheme.CreateDefault(); public static MessageBoxResult Show(string messageBoxText) { return Show(null, messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(string messageBoxText, string caption) { return Show(null, messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button) { return Show(null, messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) { return Show(null, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { return Show(null, messageBoxText, caption, button, icon, defaultResult, 0, null); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options) { return Show(null, messageBoxText, caption, button, icon, defaultResult, options, null); } public static MessageBoxResult Show(Window owner, string messageBoxText) { return Show(owner, messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption) { return Show(owner, messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button) { return Show(owner, messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon) { return Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, null); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult) { return Show(owner, messageBoxText, caption, button, icon, defaultResult, 0, null); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options) { return Show(owner, messageBoxText, caption, button, icon, defaultResult, options, null); } public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MwMessageBoxButtonText buttonText) { return Show(null, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, buttonText); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MwMessageBoxButtonText buttonText) { return Show(owner, messageBoxText, caption, button, icon, MessageBoxResult.None, 0, buttonText); } public static MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, MwMessageBoxButtonText buttonText) { return InvokeOnUiThread(() => ShowCore(owner, messageBoxText, caption, button, icon, defaultResult, options, buttonText)); } public static MessageBoxResult ShowCustom(string messageBoxText, string caption, MessageBoxImage icon, params MwMessageBoxButtonDefinition[] buttons) { return ShowCustom(null, messageBoxText, caption, icon, MessageBoxResult.None, 0, buttons); } public static MessageBoxResult ShowCustom(Window owner, string messageBoxText, string caption, MessageBoxImage icon, params MwMessageBoxButtonDefinition[] buttons) { return ShowCustom(owner, messageBoxText, caption, icon, MessageBoxResult.None, 0, buttons); } public static MessageBoxResult ShowCustom(Window owner, string messageBoxText, string caption, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, params MwMessageBoxButtonDefinition[] buttons) { return InvokeOnUiThread(() => ShowCustomCore(owner, messageBoxText, caption, icon, defaultResult, options, buttons)); } internal static T InvokeOnUiThread(Func callback) { if (callback == null) { throw new ArgumentNullException(nameof(callback)); } Application application = Application.Current; if (application == null) { return callback(); } if (application.Dispatcher == null || application.Dispatcher.CheckAccess()) { return callback(); } return application.Dispatcher.Invoke(callback); } private static MessageBoxResult ShowCore(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, MwMessageBoxButtonText buttonText) { owner = owner ?? GetActiveWindow(); List definitions = CreateButtonDefinitions(button, defaultResult, buttonText ?? DefaultButtonText).ToList(); MwMessageBoxState state = CreateState(messageBoxText, caption, icon, definitions, defaultResult, options); MwMessageBoxWindowViewModel viewModel = new MwMessageBoxWindowViewModel(state); MwMessageBoxWindow dialog = new MwMessageBoxWindow(viewModel); if (owner != null) { dialog.Owner = owner; dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; } dialog.ShowDialog(); return viewModel.Result; } private static MessageBoxResult ShowCustomCore(Window owner, string messageBoxText, string caption, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options, params MwMessageBoxButtonDefinition[] buttons) { owner = owner ?? GetActiveWindow(); List definitions = NormalizeButtonDefinitions(buttons, defaultResult).ToList(); MwMessageBoxState state = CreateState(messageBoxText, caption, icon, definitions, defaultResult, options); MwMessageBoxWindowViewModel viewModel = new MwMessageBoxWindowViewModel(state); MwMessageBoxWindow dialog = new MwMessageBoxWindow(viewModel); if (owner != null) { dialog.Owner = owner; dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; } dialog.ShowDialog(); return viewModel.Result; } private static IEnumerable CreateButtonDefinitions(MessageBoxButton button, MessageBoxResult defaultResult, MwMessageBoxButtonText buttonText) { var labels = buttonText ?? MwMessageBoxButtonText.CreateDefault(); var definitions = new List(); switch (button) { case MessageBoxButton.OK: definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true)); break; case MessageBoxButton.OKCancel: definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true)); definitions.Add(CreateDefinition(labels.Cancel, MessageBoxResult.Cancel, false, true)); break; case MessageBoxButton.YesNo: definitions.Add(CreateDefinition(labels.Yes, MessageBoxResult.Yes, true)); definitions.Add(CreateDefinition(labels.No, MessageBoxResult.No)); break; case MessageBoxButton.YesNoCancel: definitions.Add(CreateDefinition(labels.Yes, MessageBoxResult.Yes, true)); definitions.Add(CreateDefinition(labels.No, MessageBoxResult.No)); definitions.Add(CreateDefinition(labels.Cancel, MessageBoxResult.Cancel, false, true)); break; default: definitions.Add(CreateDefinition(labels.Ok, MessageBoxResult.OK, true)); break; } return NormalizeButtonDefinitions(definitions, defaultResult); } private static IEnumerable NormalizeButtonDefinitions(IEnumerable buttons, MessageBoxResult defaultResult) { var definitions = (buttons ?? Enumerable.Empty()) .Where(item => item != null) .Select(item => new MwMessageBoxButtonDefinition { Text = string.IsNullOrWhiteSpace(item.Text) ? item.Result.ToString() : item.Text, Result = item.Result, IsCancel = item.IsCancel, IsDefault = item.IsDefault, IsPrimary = item.IsPrimary, ButtonStyle = item.ButtonStyle }) .ToList(); if (definitions.Count == 0) { definitions.Add(CreateDefinition(DefaultButtonText.Ok, MessageBoxResult.OK, true)); } var targetDefault = defaultResult == MessageBoxResult.None ? definitions.FirstOrDefault(item => item.IsDefault)?.Result ?? definitions[0].Result : defaultResult; foreach (var item in definitions) { item.IsDefault = item.Result == targetDefault; } if (!definitions.Any(item => item.IsCancel)) { var cancelButton = definitions.FirstOrDefault(item => item.Result == MessageBoxResult.Cancel); if (cancelButton != null) { cancelButton.IsCancel = true; } } if (!definitions.Any(item => item.IsPrimary)) { var primary = definitions.FirstOrDefault(item => item.IsDefault) ?? definitions[0]; primary.IsPrimary = true; } foreach (var item in definitions) { item.ButtonStyle = item.ButtonStyle ?? GetButtonStyle(item.IsPrimary); } return definitions; } private static MwMessageBoxButtonDefinition CreateDefinition(string text, MessageBoxResult result, bool isPrimary = false, bool isCancel = false) { return new MwMessageBoxButtonDefinition { Text = text, Result = result, IsPrimary = isPrimary, IsDefault = isPrimary, IsCancel = isCancel, ButtonStyle = GetButtonStyle(isPrimary) }; } internal static Style GetButtonStyle(bool isPrimary) { if (Application.Current != null) { var key = isPrimary ? "SaveButtonStyle" : "SettingsButtonStyle"; var resourceStyle = Application.Current.TryFindResource(key) as Style; if (resourceStyle != null) { return resourceStyle; } } var visualTheme = VisualTheme ?? MwMessageBoxVisualTheme.CreateDefault(); var buttonTheme = isPrimary ? visualTheme.PrimaryButtonTheme : visualTheme.SecondaryButtonTheme; var style = new Style(typeof(System.Windows.Controls.Button)); style.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.BackgroundColor))); style.Setters.Add(new Setter(System.Windows.Controls.Control.BorderBrushProperty, CreateBrush(buttonTheme.BorderColor))); style.Setters.Add(new Setter(System.Windows.Controls.Control.BorderThicknessProperty, new Thickness(1))); style.Setters.Add(new Setter(System.Windows.Controls.Control.ForegroundProperty, CreateBrush(buttonTheme.ForegroundColor))); style.Setters.Add(new Setter(System.Windows.Controls.Control.FontSizeProperty, 14d)); style.Setters.Add(new Setter(System.Windows.Controls.Control.FontWeightProperty, FontWeights.SemiBold)); style.Setters.Add(new Setter(System.Windows.Controls.Control.CursorProperty, System.Windows.Input.Cursors.Hand)); var hoverTrigger = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true }; hoverTrigger.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.HoverBackgroundColor))); style.Triggers.Add(hoverTrigger); var pressedTrigger = new Trigger { Property = System.Windows.Controls.Primitives.ButtonBase.IsPressedProperty, Value = true }; pressedTrigger.Setters.Add(new Setter(System.Windows.Controls.Control.BackgroundProperty, CreateBrush(buttonTheme.PressedBackgroundColor))); style.Triggers.Add(pressedTrigger); return style; } internal static MessageBoxResult ResolveFallbackResult(MwMessageBoxState state) { if (state == null) { return MessageBoxResult.None; } if (state.DefaultResult != MessageBoxResult.None) { return state.DefaultResult; } var cancelButton = state.Buttons != null ? state.Buttons.FirstOrDefault(item => item.IsCancel) : null; if (cancelButton != null) { return cancelButton.Result; } var defaultButton = state.Buttons != null ? state.Buttons.FirstOrDefault(item => item.IsDefault) ?? state.Buttons.FirstOrDefault() : null; return defaultButton != null ? defaultButton.Result : MessageBoxResult.None; } private static Window GetActiveWindow() { if (Application.Current == null) { return null; } var active = Application.Current.Windows.OfType().FirstOrDefault(w => w.IsActive); if (active != null) { return active; } if (Application.Current.MainWindow != null && Application.Current.MainWindow.IsVisible) { return Application.Current.MainWindow; } return Application.Current.Windows.OfType() .Where(w => w.IsVisible) .OrderByDescending(w => w.IsLoaded) .FirstOrDefault(); } private static MwMessageBoxState CreateState(string message, string caption, MessageBoxImage icon, IReadOnlyList buttons, MessageBoxResult defaultResult, MessageBoxOptions options) { var palette = CreatePaletteBrushes(GetPalette(icon)); return new MwMessageBoxState { Caption = ResolveCaption(caption, icon), Message = message, IconGlyph = GetIconText(icon, IconTheme), IconPathData = GetIconPathData(icon), TimeText = DateTime.Now.ToString("HH:mm:ss"), AccentBrush = palette.AccentBrush, IconBackgroundBrush = palette.IconBackgroundBrush, IconForegroundBrush = palette.IconForegroundBrush, Buttons = buttons, DefaultResult = defaultResult, MessageTextAlignment = (options & MessageBoxOptions.RightAlign) == MessageBoxOptions.RightAlign ? TextAlignment.Right : TextAlignment.Left, WindowFlowDirection = (options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading ? FlowDirection.RightToLeft : FlowDirection.LeftToRight, MessageFlowDirection = (options & MessageBoxOptions.RtlReading) == MessageBoxOptions.RtlReading ? FlowDirection.RightToLeft : FlowDirection.LeftToRight }; } private static string ResolveCaption(string caption, MessageBoxImage icon) { if (!string.IsNullOrWhiteSpace(caption)) { return caption; } switch (icon) { case MessageBoxImage.Warning: return "警告提示"; case MessageBoxImage.Error: return "报警提示"; case MessageBoxImage.Information: return "信息提示"; case MessageBoxImage.Question: return "操作确认"; default: return "提示"; } } private static string GetIconText(MessageBoxImage icon, MwMessageBoxIconTheme iconTheme) { var theme = iconTheme ?? MwMessageBoxIconTheme.CreateDefault(); switch (icon) { case MessageBoxImage.None: return theme.NoneGlyph; case MessageBoxImage.Warning: return theme.WarningGlyph; case MessageBoxImage.Error: return theme.ErrorGlyph; case MessageBoxImage.Information: return theme.InformationGlyph; case MessageBoxImage.Question: return theme.QuestionGlyph; default: return theme.NoneGlyph; } } private static string GetIconPathData(MessageBoxImage icon) { switch (icon) { case MessageBoxImage.Warning: return "M11,4 H13 V14 H11 Z M11,16 H13 V18 H11 Z"; case MessageBoxImage.Error: return "M7.76,6.34 L12,10.59 L16.24,6.34 L17.66,7.76 L13.41,12 L17.66,16.24 L16.24,17.66 L12,13.41 L7.76,17.66 L6.34,16.24 L10.59,12 L6.34,7.76 Z"; case MessageBoxImage.Information: return "M11,5 H13 V7 H11 Z M11,9 H13 V19 H11 Z"; case MessageBoxImage.Question: return "M10.2,8.8 C10.27,7.69 11.17,6.82 12.3,6.82 C13.46,6.82 14.36,7.66 14.36,8.75 C14.36,9.52 13.96,10.12 13.02,10.82 C11.74,11.78 11.1,12.65 11.1,14.35 L12.9,14.35 C12.9,13.26 13.27,12.74 14.1,12.09 C15.29,11.17 16,10.14 16,8.72 C16,6.69 14.37,5 12.3,5 C10.23,5 8.56,6.63 8.4,8.8 Z M11.05,16.2 H13.15 V18.3 H11.05 Z"; default: return "M8,11 H16 V13 H8 Z"; } } private static MwMessageBoxColorPalette GetPalette(MessageBoxImage icon) { var visualTheme = VisualTheme ?? MwMessageBoxVisualTheme.CreateDefault(); switch (icon) { case MessageBoxImage.Warning: return CreatePalette(visualTheme.WarningPalette, visualTheme.NonePalette); case MessageBoxImage.Error: return CreatePalette(visualTheme.ErrorPalette, visualTheme.NonePalette); case MessageBoxImage.Information: return CreatePalette(visualTheme.InformationPalette, visualTheme.NonePalette); case MessageBoxImage.Question: return CreatePalette(visualTheme.QuestionPalette, visualTheme.NonePalette); default: return CreatePalette(visualTheme.NonePalette, MwMessageBoxVisualTheme.CreateDefault().NonePalette); } } private static MwMessageBoxPaletteBrushes CreatePaletteBrushes(MwMessageBoxColorPalette palette) { return new MwMessageBoxPaletteBrushes(palette); } private static MwMessageBoxColorPalette CreatePalette(MwMessageBoxColorPalette palette, MwMessageBoxColorPalette fallbackPalette) { var resolvedFallback = fallbackPalette ?? MwMessageBoxVisualTheme.CreateDefault().NonePalette; var resolvedPalette = palette ?? resolvedFallback; return new MwMessageBoxColorPalette( resolvedPalette.AccentColor ?? resolvedFallback.AccentColor, resolvedPalette.IconBackgroundColor ?? resolvedFallback.IconBackgroundColor, resolvedPalette.IconForegroundColor ?? resolvedFallback.IconForegroundColor); } private static SolidColorBrush CreateBrush(string color) { return (SolidColorBrush)new BrushConverter().ConvertFromString(color); } private sealed class MwMessageBoxPaletteBrushes { public MwMessageBoxPaletteBrushes(MwMessageBoxColorPalette palette) { var resolvedPalette = palette ?? MwMessageBoxVisualTheme.CreateDefault().NonePalette; AccentBrush = CreateBrush(resolvedPalette.AccentColor ?? "#9CA3AF"); IconBackgroundBrush = CreateBrush(resolvedPalette.IconBackgroundColor ?? "#F3F4F6"); IconForegroundBrush = CreateBrush(resolvedPalette.IconForegroundColor ?? "#6B7280"); } public Brush AccentBrush { get; } public Brush IconBackgroundBrush { get; } public Brush IconForegroundBrush { get; } private static SolidColorBrush CreateBrush(string color) { return (SolidColorBrush)new BrushConverter().ConvertFromString(color); } } } }