如何解决显示模态对话框消息并等待后面的blazor代码的用户回答
我在Blazor
应用中关注this guide,以显示模式对话框。我知道Blazored.Modal,此处并未将其用于学习目的。
这里的要点是,我想将其用于某种形式的用户验证,并且仅在用户同意时才执行代码。我使用ModalService
在另一个MyBackgroundService
中显示提示,做了一些需要用户选择的事情。
这是主页代码:
@page "/"
@inject ModalService _modalService
@inject MyBackgroundService _myService
<div>
<button @onclick="onShowClick" class="btn btn-primary">Show</button>
<button @onclick="onRunClick" class="btn btn-primary">Run</button>
</div>
@code {
protected async Task onShowClick() {
// shows MyControl in a modal form => working just great!
_modalService.Show(typeof(MyControl));
}
protected async Task onRunClick() {
await _myService.Run();
}
}
这里是ModalService
类的代码:
public class ModalService {
public event Action<Type> OnShow;
public event Action OnClose;
public void Show(Type contentType) {
if (contentType.BaseType != typeof(ComponentBase)) {
throw new ArgumentException($"{contentType.FullName} must be a Blazor Component");
}
OnShow?.Invoke(contentType);
}
public void Close() {
OnClose?.Invoke();
}
}
这是MyBackgroundService
类的示例代码:
public class MyBackgroundService {
private readonly ModalService _modalService;
public CalSyncerService(ModalService modalService) {
_modalService = modalService;
}
public async Task Run() {
var processResult1 = await firstLongProcess();
string userAnswer = "Ok";
if (processResult1 != true) {
// something went wrong so far => it might be risky to continue => ask user if Ok...
// of course,we're not awaiting the user answer here,this is what I need to correct!!
_modalService.Show(typeof(MyControl));
}
if (userAnswer == "Ok") {
await secondProcess();
}
}
}
等待用户回答的一种干净方法是什么?使用一种动作,或者甚至更好的一种async
方法,显示模式对话框并等待对话框关闭以返回答案?
解决方法
因此,我的CLEAN处理方式涉及具有布局引擎的Component,它也做其他事情,例如显示“工作”模态,并使用包装,以免残留。
首先使用剃刀组件:
@inherits LayoutEngineBase
@if (Spinning)
{
<div id="workingModal">
<h1>@Message</h1>
</div>
}
@if (NeedsConfirmation)
{
<div id="confirmModal">
<div class="card">
<div class="card-body">
<h3>@ConfirmationMessage</h3>
</div>
<div class="card-footer">
<button class="btn btn-success" @onclick="ConfirmYes">Ok</button>
<button class="btn btn-danger" @onclick="ConfirmNo">Cancel</button>
</div>
</div>
</div>
}
@ChildContent
然后建立基础:
using Microsoft.AspNetCore.Components;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Web.Shared
{
public class LayoutEngineBase : ComponentBase
{
/// <summary>
/// This is used for the contained Razor markup.
/// </summary>
[Parameter]
public RenderFragment ChildContent { get; set; }
/// <summary>
/// This fires when something has changed,useful with Cascaded Pages
/// </summary>
[Parameter]
public EventCallback OnStateChanged { get; set; }
/// <summary>
/// Bind this to whatever needs to change when working is in progress
/// </summary>
public bool Spinning { get; internal set; } = false;
/// <summary>
/// Bind this to whatever needs to change when a confirmation is required
/// </summary>
public bool NeedsConfirmation { get; internal set; } = false;
/// <summary>
/// MarkupString will render raw HTML to Razor.
/// </summary>
public MarkupString Message { get; internal set; }
protected MarkupString ConfirmationMessage { get; private set; }
/// <summary>
/// Call this internally to for a re-render StateHasChanged()
/// </summary>
internal async virtual void RaiseChange()
{
await OnStateChanged.InvokeAsync();
}
private CancellationTokenSource FinishConfirm;
private bool DialogResponse;
private string _stationName;
public string StationName
{
get => _stationName;
set
{
_stationName = value;
RaiseChange();
}
}
/// <summary>
/// Wrap this in a using to switch spinning state on and off at bracket boundaries
/// </summary>
/// <param name="message">Used to set the display message during working.</param>
/// <returns>New IDisposable Worker</returns>
public Worker Working(string message = null) => new Worker(this,message ?? "Working");
/// <summary>
/// Await this to wait for a user response.
/// </summary>
/// <param name="message"></param>
/// <returns>True for Ok,False for Cancel</returns>
public async Task<bool> ShowConfirmAsync(string message)
{
ConfirmationMessage = new(message);
NeedsConfirmation = true;
try
{
using (FinishConfirm = new())
{
await Task.Delay(-1,FinishConfirm.Token);
}
}
catch (TaskCanceledException) { } // we want to cancel it.
return DialogResponse;
}
protected void ConfirmYes()
{
ConfirmDialog(true);
}
protected void ConfirmNo()
{
ConfirmDialog(false);
}
private void ConfirmDialog(bool confirmation)
{
DialogResponse = confirmation;
if (FinishConfirm.Token.CanBeCanceled)
{
FinishConfirm.Cancel();
}
NeedsConfirmation = false;
RaiseChange();
}
}
/// <summary>
/// When created this will start the spinning,when disposed it will stop it. Not really needed by external code,but need to be public for accessibility level.
/// </summary>
public sealed class Worker : IDisposable
{
private LayoutEngineBase _parent;
public Worker(LayoutEngineBase parent,string message)
{
_parent = parent;
_parent.Message = new MarkupString($" {message}…");
_parent.Spinning = true;
_parent.RaiseChange();
}
public void Dispose()
{
_parent.Spinning = false;
_parent.RaiseChange();
}
}
}
然后可以用它包装MainLayout.razor:
<LayoutEngine @ref="layoutEngine" OnStateChanged="LayoutEngineStateChanged">
<div class="main grid">
<div class="top-row px-4">
...Navigation...
</div>
<div class="content p-4">
<CascadingValue Value=layoutEngine>
@Body
</CascadingValue>
</div>
</div>
</LayoutEngine>
注意,我已经@ref layoutEngine并对其进行了级联。
MainLayout的代码:
@code
{
protected LayoutEngineBase layoutEngine = new();
protected void LayoutEngineStateChanged()
{
StateHasChanged();
}
protected async void LogOut()
{
var confirm = await layoutEngine.ShowConfirmAsync("Are you sure?");
if (confirm)
{
await AuthenticationStateProvider.LogOutUserAsync();
StateHasChanged();
NavigationManager.NavigateTo("/");
}
}
}
您可以看到LayoutEngine组件具有一个OnStateChanged,然后可以使用它来告诉MainLayout StateHasChanged();
这里您应该感兴趣的是LogOut函数,这里的var Confirm等待ShowConfirm,它仅在有人单击“确定”或“取消”时结束任务。
此外,只要您接受级联参数layoutEngine,“工作”选项就可以与以下代码一起使用:
using (layoutEngine.Working("Doing Stuff"))
{
Do Stuff...
}
这显示了一个模态,上面写着“正在做的事情”,直到使用结束。
这显然需要一些CSS,我不会在这里发布,每个人都不一样。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。