using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using LibationWinForms.AvaloniaUI.ViewModels.Dialogs; using LibationWinForms.AvaloniaUI.Views.Dialogs; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace LibationWinForms.AvaloniaUI { public enum DialogResult { None = 0, OK = 1, Cancel = 2, Abort = 3, Retry = 4, Ignore = 5, Yes = 6, No = 7, TryAgain = 10, Continue = 11 } public enum MessageBoxIcon { None = 0, Error = 16, Hand = 16, Stop = 16, Question = 32, Exclamation = 48, Warning = 48, Asterisk = 64, Information = 64 } public enum MessageBoxButtons { OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel, CancelTryContinue } public enum MessageBoxDefaultButton { Button1, Button2 = 256, Button3 = 512, } public class MessageBox { /// Displays a message box with the specified text, caption, buttons, icon, and default button. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values that specifies which icon to display in the message box. /// One of the values that specifies the default button for the message box. /// One of the values. /// /// is not a member of . /// -or- /// is not a member of . /// -or- /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. public static async Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) { return await ShowCore(null, text, caption, buttons, icon, defaultButton); } /// Displays a message box with specified text, caption, buttons, and icon. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values that specifies which icon to display in the message box. /// One of the values. /// The parameter specified is not a member of . /// -or- /// The parameter specified is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. public static async Task Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { return await ShowCore(null, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); } /// Displays a message box with specified text, caption, and buttons. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values. /// The parameter specified is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. public static async Task Show(string text, string caption, MessageBoxButtons buttons) { return await ShowCore(null, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// Displays a message box with specified text and caption. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values. public static async Task Show(string text, string caption) { return await ShowCore(null, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// Displays a message box with specified text. /// The text to display in the message box. /// One of the values. public static async Task Show(string text) { return await ShowCore(null, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// Displays a message box in front of the specified object and with the specified text, caption, buttons, icon, default button, and options. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values that specifies which icon to display in the message box. /// One of the values the specifies the default button for the message box. /// One of the values that specifies which display and association options will be used for the message box. You may pass in 0 if you wish to use the defaults. /// One of the values. /// /// is not a member of . /// -or- /// is not a member of . /// -or- /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. /// /// -or- /// specified an invalid combination of . public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) { return await ShowCore(owner, text, caption, buttons, icon, defaultButton); } /// Displays a message box in front of the specified object and with the specified text, caption, buttons, and icon. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values that specifies which icon to display in the message box. /// One of the values. /// /// is not a member of . /// -or- /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) { return await ShowCore(owner, text, caption, buttons, icon, MessageBoxDefaultButton.Button1); } /// Displays a message box in front of the specified object and with the specified text, caption, and buttons. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values that specifies which buttons to display in the message box. /// One of the values. /// /// is not a member of . /// An attempt was made to display the in a process that is not running in User Interactive mode. This is specified by the property. public static async Task Show(Window owner, string text, string caption, MessageBoxButtons buttons) { return await ShowCore(owner, text, caption, buttons, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// Displays a message box in front of the specified object and with the specified text and caption. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// The text to display in the title bar of the message box. /// One of the values. public static async Task Show(Window owner, string text, string caption) { return await ShowCore(owner, text, caption, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } /// Displays a message box in front of the specified object and with the specified text. /// An implementation of that will own the modal dialog box. /// The text to display in the message box. /// One of the values. public static async Task Show(Window owner, string text) { return await ShowCore(owner, text, string.Empty, MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1); } private static async Task ShowCore(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) { if (Avalonia.Threading.Dispatcher.UIThread.CheckAccess()) return await ShowCore2(owner, message, caption, buttons, icon, defaultButton); else return await Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => ShowCore2(owner, message, caption, buttons, icon, defaultButton)); } private static async Task ShowCore2(Window owner, string message, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton) { var dialog = new MessageBoxWindow(); var vm = new MessageBoxViewModel(message, caption, buttons, icon, defaultButton); dialog.DataContext = vm; dialog.CanResize = false; var thisScreen = (owner ?? dialog).Screens.ScreenFromVisual(owner ?? dialog); var tbx = dialog.FindControl("messageTextBlock"); tbx.Text = message; var maxSize = new Size(0.6 * thisScreen.Bounds.Width - 72, 0.9 * thisScreen.Bounds.Height); var desiredMax = maxSize; //Try to minimize the TextBlock area. List<(double, Size)> areas = new(); for (int i = 0; i < 20; i++) { tbx.Measure(desiredMax); var area = tbx.DesiredSize.Width * tbx.DesiredSize.Height; areas.Add((area, new Size(tbx.DesiredSize.Width, tbx.DesiredSize.Height))); if (tbx.DesiredSize.Height < maxSize.Height - 20) { if (desiredMax.Width / 2 < tbx.MinWidth) desiredMax = new Size(desiredMax.Width * 1.5 + 1, desiredMax.Height); else desiredMax = new Size(desiredMax.Width / 2, desiredMax.Height); } } var min = areas.Min(a => a.Item1); var mindim = areas.First(a => a.Item1 == min); var desiredSize = new Size(dialog.MinWidth - tbx.MinWidth + mindim.Item2.Width, dialog.MinHeight - tbx.MinHeight + mindim.Item2.Height); dialog.Width = desiredSize.Width; dialog.Height = desiredSize.Height; tbx.Width = mindim.Item2.Width; tbx.Height = mindim.Item2.Height; if (owner is null) { if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return await dialog.ShowDialog(desktop.MainWindow); } else { var window = new Window { IsVisible = false, Height = 1, Width = 1, SystemDecorations = SystemDecorations.None, ShowInTaskbar = false }; window.Show(); var result = await dialog.ShowDialog(window); window.Close(); return result; } } else { return await dialog.ShowDialog(owner); } } } }