From 530aca4f4d7bca693f49f715a03cb778b8e34912 Mon Sep 17 00:00:00 2001 From: Mbucari <37587114+Mbucari@users.noreply.github.com> Date: Sat, 29 Nov 2025 15:31:07 -0700 Subject: [PATCH] Fix MessageBox launch error on macOS --- Source/LibationAvalonia/MessageBox.cs | 61 ++++++++++++++++----------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/Source/LibationAvalonia/MessageBox.cs b/Source/LibationAvalonia/MessageBox.cs index e94c7f0f..cbc56e94 100644 --- a/Source/LibationAvalonia/MessageBox.cs +++ b/Source/LibationAvalonia/MessageBox.cs @@ -11,10 +11,11 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Avalonia.Platform; +#nullable enable namespace LibationAvalonia { - public class MessageBox { public static Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) @@ -27,15 +28,15 @@ namespace LibationAvalonia => ShowCoreAsync(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); public static Task Show(string text) => ShowCoreAsync(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) + public static Task Show(Window? owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) => ShowCoreAsync(owner, text, caption, buttons, icon, defaultButton, saveAndRestorePosition); - public static Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) + public static Task Show(Window? owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) => ShowCoreAsync(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); - public static Task Show(Window owner, string text, string caption, MessageBoxButtons buttons) + public static Task Show(Window? owner, string text, string caption, MessageBoxButtons buttons) => ShowCoreAsync(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static Task Show(Window owner, string text, string caption) + public static Task Show(Window? owner, string text, string caption) => ShowCoreAsync(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); - public static Task Show(Window owner, string text) + public static Task Show(Window? owner, string text) => ShowCoreAsync(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); public static async Task VerboseLoggingWarning_ShowIfTrue() @@ -58,7 +59,7 @@ namespace LibationAvalonia /// /// Note: the format field should use {0} and NOT use the `$` string interpolation. Formatting is done inside this method. /// - public static async Task ShowConfirmationDialog(Window owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + public static async Task ShowConfirmationDialog(Window? owner, IEnumerable libraryBooks, string format, string title, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { if (libraryBooks is null || !libraryBooks.Any()) return DialogResult.Cancel; @@ -88,7 +89,7 @@ namespace LibationAvalonia /// The text to display in the message box. /// The text to display in the title bar of the message box. /// Exception to log. - public static async Task ShowAdminAlert(Window owner, string text, string caption, Exception exception) + public static async Task ShowAdminAlert(Window? owner, string text, string caption, Exception exception) { // for development and debugging, show me what broke! if (System.Diagnostics.Debugger.IsAttached) @@ -106,7 +107,7 @@ namespace LibationAvalonia await DisplayWindow(form, owner); } - private static async Task ShowCoreAsync(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) + private static async Task ShowCoreAsync(Window? owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) => await Dispatcher.UIThread.InvokeAsync(async () => { owner = owner?.IsLoaded is true ? owner : null; @@ -114,10 +115,8 @@ namespace LibationAvalonia return await DisplayWindow(dialog, owner); }); - private static MessageBoxWindow CreateMessageBox(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) + private static MessageBoxWindow CreateMessageBox(Window? owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, bool saveAndRestorePosition = true) { - owner ??= (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).MainWindow; - var dialog = new MessageBoxWindow(saveAndRestorePosition); var vm = new MessageBoxViewModel(message, caption, buttons, icon, defaultButton); @@ -125,18 +124,12 @@ namespace LibationAvalonia dialog.ControlToFocusOnShow = dialog.FindControl(defaultButton.ToString()); dialog.CanResize = false; dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; - var tbx = dialog.FindControl("messageTextBlock"); + var tbx = dialog.messageTextBlock; tbx.MinWidth = vm.TextBlockMinWidth; tbx.Text = message; - var thisScreen = owner.Screens?.ScreenFromVisual(owner); - - var maxSize - = thisScreen is null ? owner.ClientSize - : new Size(0.20 * thisScreen.Bounds.Width, 0.9 * thisScreen.Bounds.Height - 55); - - var desiredMax = new Size(maxSize.Width, maxSize.Height); + var desiredMax = GetMaxMessageBoxSizeFromOwner(owner); tbx.Measure(desiredMax); @@ -152,13 +145,34 @@ namespace LibationAvalonia dialog.Width = dialog.MinWidth; return dialog; } - private static async Task DisplayWindow(DialogWindow toDisplay, Window owner) + + private static Size GetMaxMessageBoxSizeFromOwner(TopLevel? owner) + { + if (owner is null && App.Current is IClassicDesktopStyleApplicationLifetime lt) + { + //The Windows enumeration will only contain active (non-disposed) windows. + //If none are available, the last disposed window may still be in MainWindow + //Just be careful what you use it for. It will still have Screens, but + //ScreenFromTopLevel can't be used on macOS. + owner = lt.Windows.FirstOrDefault() ?? lt.MainWindow; + } + if (owner?.Screens is Screens screens) + { + var mainScreen = owner?.PlatformImpl is null ? screens.Primary : screens.ScreenFromTopLevel(owner); + if (mainScreen is not null) + return new Size(0.20 * mainScreen.Bounds.Width, 0.9 * mainScreen.Bounds.Height - 55); + } + + return owner?.ClientSize ?? new Size(800, 600); + } + + private static async Task DisplayWindow(DialogWindow toDisplay, Window? owner) { if (owner is null) { - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - if (desktop.MainWindow.IsLoaded) + if (desktop.MainWindow?.IsLoaded is true) return await toDisplay.ShowDialog(desktop.MainWindow); else { @@ -185,7 +199,6 @@ namespace LibationAvalonia window.Close(); return result; } - } else {