
Готовое решение, которому я планирую оказать поддержку и обновление, и буду рад, если кто-нибудь присоединиться, можно найти на nuget и gitlab.
Моя цель приблизиться к стандартному виндовому MsgBox по крайней мере по опыту использования.
Итак:
Вызываем
MessageBox.ShowForResult("test","Wanna test smth?",MessageBox.MessageBoxButtons.OkCancel);
и получаем готовое окошко с заголовком и текстовым содержимым. (Windows 10, Ubuntu 18.04)


Класс MessageBox содержит 3 метода:
ShowForResult — возвращает результат нажатия клавиш
ShowDialog — возвращает результат и делает окно MessageBox диалоговым для выбранного родительского окна
Show — отображает окно игнорируя результат нажатия клавиш
API
Внутри любого метода создается окно,
var messageBox = new MessageBox();
которому устанавливается контент.
messageBox.Content = CreateBaseMsgBox(text, buttons, messageBox);
Контентом в данном случае является Grid, включающий в себя две строки: первая для текстового поля:
var textBlock = new TextBlock(); textBlock.Text = text; textBlock.TextAlignment = TextAlignment.Center; textBlock.TextWrapping = TextWrapping.Wrap; Grid.SetRow(textBlock,0); grid.Children.Add(textBlock);
вторая для вложенного grid с кнопками:
var btnGrid = GetButtonGrid(GetButton(window, MessageBoxResult.Yes), GetButton(window,MessageBoxResult.No)); Grid.SetRow(btnGrid,1); grid.Children.Add(btnGrid);
private static Grid GetButtonGrid(params Button[] buttons) { var grid = new Grid(); List<ColumnDefinition> definitions = new List<ColumnDefinition>(); for (int i = 0; i < buttons.Length; i++) { definitions.Add(new ColumnDefinition{Width = new GridLength(5)}); definitions.Add(new ColumnDefinition{Width = new GridLength(1,GridUnitType.Star)}); } definitions.Add(new ColumnDefinition{Width = new GridLength(5)}); grid.ColumnDefinitions.AddRange(definitions); var j = 1; foreach (var btn in buttons) { Grid.SetColumn(btn,j); j += 2; grid.Children.Add(btn); } return grid; }
Такой динамический подход позволяет добавлять неограниченное количество кнопок и расширять возможности MessageBox без больших изменений.
Функциональность кнопок задается методом:
GetButton(MessageBox window,MessageBoxResult result)
private static Button GetButton(MessageBox window,MessageBoxResult result) { var btn = new Button(); btn.Content = result.ToString(); btn.Click += (_, __) => { window.Res = result; window.Close(); }; return btn; }
Метод принимает окно, с которым будут манипулировать кнопки, и результат, возвращаемый ими.
И, последнее, что необходимо рассмотреть — фрагмент кода, что обеспечивает результат нажатия кнопки:
var tcs = new TaskCompletionSource<MessageBoxResult>(); messageBox.Closed += delegate { tcs.TrySetResult(messageBox.Res); }; ... return tcs.Task;
В результате мы получаем различные простейшие окошки с кнопками, что позволит создавать кроссплатформенные MessageBox:

UPD
Добавлен метод, что пытается вызвать реализацию нативных окон, если не справляется, то вызывает окна, представленные выше.
Отдельное спасибо пользователю worldbeater.

