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);
}
}
}