using DevExpress.Blazor; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components; namespace TIAMSharedUI.Shared.Components { /// /// A MessageBox (async and synchronized) component to provide a way to show informational messages. /// public partial class PopupMessageBox { public static readonly string ButtonOk = "Ok"; public static readonly string ButtonCancel = "Cancel"; public static readonly string ButtonYes = "Yes"; public static readonly string ButtonNo = "No"; [Inject] private NavigationManager Navigation { get; set; } = default!; /// /// The MessageBox popup. This is a DxPopup that is called asynchronously so it is displayed and control returns /// to the caller. /// private DxPopup MessageBoxPopup { get; set; } = default!; /// /// The header text in the MessageBox popup. This is a MarkupString so do not put any user entered text in this! /// private string HeaderText { get; set; } = string.Empty; /// /// The message text in the MessageBox popup. This is a MarkupString so do not put any user entered text in this! /// private string MessageHtml { get; set; } = string.Empty; private Func? OnClick { get; set; } private Func? OnClose { get; set; } /// /// This is passed in in the call to Show() and returned in the calls to OnClick() and OnClose(). /// private object? Tag { get; set; } /// /// Used to make the popup synchronous. /// private TaskCompletionSource _taskCompletionSource = new(); /// public PopupMessageBox() { ButtonVisible = new bool[4]; ButtonText = new string[4]; } /// /// Displays the MessageBox. This is a static object so you can't create multiple instances of it. But you /// can create another instance in the onClick or onCLose calls as the existing instance will be closed by /// then. /// /// The header text in the message box. /// The main message in the message box. This is treated as html /// so use HttpUtility.HtmlEncode() on any user generated text in the message. /// Caller defined data returned in the OnClick/OnClose calls. /// Will call this method when a button is clicked. Passes the button text as the parameter. /// Will call this when the popup is closed. Including after receiving the onClick call. /// The text for the button(s). Can be 1 .. 4 buttons. /// The task for the underlying DxPopup.ShowAsync() call. public Task ShowAsync(string header, string message, object? tag, Func? onClick, Func? onClose, params string[] buttonText) { HeaderText = header; MessageHtml = message; Tag = tag; OnClick = onClick; OnClose = onClose; if (buttonText.Length == 0 || buttonText.Length > 4) throw new ArgumentOutOfRangeException(nameof(buttonText), "Must have between 1 and 4 buttons"); Array.Clear(ButtonVisible); Array.Clear(ButtonText); for (var index = 0; index < buttonText.Length; index++) { ButtonVisible[index] = true; ButtonText[index] = buttonText[index]; } StateHasChanged(); return MessageBoxPopup.ShowAsync(); } /// /// Displays the MessageBox. Then when click OK, goes to the url. This is a static object so you can't create /// multiple instances of it. /// /// The header text in the message box. /// The main message in the message box. This is treated as html /// so use HttpUtility.HtmlEncode() on any user generated text in the message. /// The url to navigate to when click OK. /// The task for the underlying DxPopup.ShowAsync() call. public Task ShowThenRedirectAsync(string header, string message, string url) { return ShowAsync(header, message, null, (_, _) => { Navigation.NavigateTo(url, false); return Task.CompletedTask; }, null, PopupMessageBox.ButtonOk); } /// /// Displays the MessageBox synchronously. Returns the text of the button clicked. This is a static object /// so you can't create multiple instances of it. But you can create another instance when it returns as the /// existing instance will be closed by then. /// /// The header text in the message box. /// The main message in the message box. This is treated as html /// so use HttpUtility.HtmlEncode() on any user generated text in the message. /// The text for the button(s). Can be 1 .. 4 buttons. /// The text of the button clicked. public Task Show(string header, string message, params string[] buttonText) { _taskCompletionSource = new TaskCompletionSource(); ShowAsync(header, message, null, ShowOnClick, null, buttonText); // we return the Task from the TaskCompletionSource that is not completed return _taskCompletionSource.Task; } private Task ShowOnClick(string buttonText, object? tag) { // as this is called from the OnClick handler, the popup has been closed. // sets the TaskCompletionSource to completed. Any await-ers will now complete _taskCompletionSource.SetResult(buttonText); return Task.FromResult(_taskCompletionSource); } private string[] ButtonText { get; } private bool[] ButtonVisible { get; } private async Task Button0Click(MouseEventArgs arg) { // need to close before calling OnClick because OnClick may call ShowAsync again await MessageBoxPopup.CloseAsync(); if (OnClick != null) await OnClick.Invoke(ButtonText[0], Tag); } private async Task Button1Click(MouseEventArgs arg) { // need to close before calling OnClick because OnClick may call ShowAsync again await MessageBoxPopup.CloseAsync(); if (OnClick != null) await OnClick.Invoke(ButtonText[1], Tag); } private async Task Button2Click(MouseEventArgs arg) { // need to close before calling OnClick because OnClick may call ShowAsync again await MessageBoxPopup.CloseAsync(); if (OnClick != null) await OnClick.Invoke(ButtonText[2], Tag); } private async Task Button3Click(MouseEventArgs arg) { // need to close before calling OnClick because OnClick may call ShowAsync again await MessageBoxPopup.CloseAsync(); if (OnClick != null) await OnClick.Invoke(ButtonText[3], Tag); } private async Task PopupClosed(PopupClosedEventArgs arg) { // need to close before calling OnClose because OnClose may call ShowAsync again await MessageBoxPopup.CloseAsync(); if (OnClose != null) await OnClose.Invoke(Tag); } } }