TourIAm/TIAMSharedUI/Shared/Components/PopupMessageBox.razor.cs

187 lines
8.1 KiB
C#

using DevExpress.Blazor;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components;
namespace TIAMSharedUI.Shared.Components
{
/// <summary>
/// A MessageBox (async and synchronized) component to provide a way to show informational messages.
/// </summary>
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!;
/// <summary>
/// The MessageBox popup. This is a DxPopup that is called asynchronously so it is displayed and control returns
/// to the caller.
/// </summary>
private DxPopup MessageBoxPopup { get; set; } = default!;
/// <summary>
/// The header text in the MessageBox popup. This is a MarkupString so do not put any user entered text in this!
/// </summary>
private string HeaderText { get; set; } = string.Empty;
/// <summary>
/// The message text in the MessageBox popup. This is a MarkupString so do not put any user entered text in this!
/// </summary>
private string MessageHtml { get; set; } = string.Empty;
private Func<string, object?, Task>? OnClick { get; set; }
private Func<object?, Task>? OnClose { get; set; }
/// <summary>
/// This is passed in in the call to Show() and returned in the calls to OnClick() and OnClose().
/// </summary>
private object? Tag { get; set; }
/// <summary>
/// Used to make the popup synchronous.
/// </summary>
private TaskCompletionSource<string> _taskCompletionSource = new();
/// <inheritdoc />
public PopupMessageBox()
{
ButtonVisible = new bool[4];
ButtonText = new string[4];
}
/// <summary>
/// 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.
/// </summary>
/// <param name="header">The header text in the message box.</param>
/// <param name="message">The main message in the message box. This is treated as html
/// so use <code>HttpUtility.HtmlEncode()</code> on any user generated text in the message.</param>
/// <param name="tag">Caller defined data returned in the OnClick/OnClose calls.</param>
/// <param name="onClick">Will call this method when a button is clicked. Passes the button text as the parameter.</param>
/// <param name="onClose">Will call this when the popup is closed. Including after receiving the onClick call.</param>
/// <param name="buttonText">The text for the button(s). Can be 1 .. 4 buttons.</param>
/// <returns>The task for the underlying DxPopup.ShowAsync() call.</returns>
public Task<bool> ShowAsync(string header, string message, object? tag, Func<string, object?, Task>? onClick,
Func<object?, Task>? 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();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="header">The header text in the message box.</param>
/// <param name="message">The main message in the message box. This is treated as html
/// so use <code>HttpUtility.HtmlEncode()</code> on any user generated text in the message.</param>
/// <param name="url">The url to navigate to when click OK.</param>
/// <returns>The task for the underlying DxPopup.ShowAsync() call.</returns>
public Task<bool> ShowThenRedirectAsync(string header, string message, string url)
{
return ShowAsync(header, message, null,
(_, _) =>
{
Navigation.NavigateTo(url, false);
return Task.CompletedTask;
},
null, PopupMessageBox.ButtonOk);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="header">The header text in the message box.</param>
/// <param name="message">The main message in the message box. This is treated as html
/// so use <code>HttpUtility.HtmlEncode()</code> on any user generated text in the message.</param>
/// <param name="buttonText">The text for the button(s). Can be 1 .. 4 buttons.</param>
/// <returns>The text of the button clicked.</returns>
public Task<string> Show(string header, string message, params string[] buttonText)
{
_taskCompletionSource = new TaskCompletionSource<string>();
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);
}
}
}