Blazor 的确认对话框,其中包含对话框结果

Confirmation dialog for Blazor with dialog result

提问人:Single Step Debugger 提问时间:6/13/2023 更新时间:6/14/2023 访问量:357

问:

我正在尝试在 Blazor 中创建类似于我们在 JS 中的通用提示 dlg。这是我所追求的行为:

我们提示 bool 结果 = await JS。InvokeAsync(“确认”, $“你确定吗?”);

我们等待结果,直到用户单击“是”或“否”。

if(结果) { 做 }

我创建了对话框,但它从不等待用户的输入。下面是带有 Bootstrap 模式的对话框组件:

@using System.Threading

<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay" aria-hidden="true" data-toggle="modal">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header blue-dlg">
                <p class="modal-title">@Title</p>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"  @onclick="() => CloseModal()">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body dlg-validation">
                <p>@Message</p>
            </div>
            <div class="modal-footer justify-content-center">
                @{
                    if (DT == DialogTypes.Alert)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal()">Close</button>
                    }
                    else if (DT == DialogTypes.Prompt)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => OnConfirm(true)">Yes</button>
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => OnConfirm(false)">No</button>
                    }
                }
            </div>
        </div>
    </div>
</div>

<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>


@code {

    public enum DialogTypes 
    {
        Alert = 0,
        Prompt
    }

    private DialogTypes DT = DialogTypes.Alert;
    private bool confirmed = false;
    public Guid Guid = Guid.NewGuid();
    public string ModalDisplay = "none;";
    public string ModalClass = "";
    public bool ShowBackdrop = false;

    public string Title { get; set; }
    public string Message { get; set; }



    public async Task<bool> PromptAsync(string message, string title)
    {
        DT = DialogTypes.Prompt;
        Title = title;
        Message = message;
        ModalDisplay = "block;";
        await Task.Delay(100);
        ModalClass = "show";
        StateHasChanged();

        return confirmed;
    }

    public async Task AlertAsync(string message, string title)
    {
        Title = title;
        Message = message;
        ModalDisplay = "block;";
        await Task.Delay(100);
        ModalClass = "show";
        StateHasChanged();
    }

    public async Task CloseModal()
    {
        ModalClass = "";
        await Task.Delay(250);
        ModalDisplay = "none;";
        StateHasChanged();
    }

    private async Task OnConfirm(bool confirm)
    {
        confirmed = confirm;

        await CloseModal();
    }
}
多线程 ASP.NET-Core 回调 Blazor

评论


答:

0赞 MrC aka Shaun Curtis 6/14/2023 #1

您需要生成一个手动控制的运行任务,并将其交还给调用方。然后,他们可以等待任务,并且只有在您关闭对话框并将任务设置为“已完成”时才能自行完成。

为此,您可以使用类的服务。TaskCompletionSource

以下是在对话框中执行此操作的方法。

@using System.Threading

<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay" aria-hidden="true" data-toggle="modal">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header blue-dlg">
                <p class="modal-title">@Title</p>
                @{
                    if (DT == DialogTypes.Alert)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal()">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    }
                    else if (DT == DialogTypes.Prompt)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal(false)">
                            <span aria-hidden="true">
                                &times;
                            </span>
                        </button>
                    }
                }
            </div>
            <div class="modal-body dlg-validation">
                <p>@Message</p>
            </div>
            <div class="modal-footer justify-content-center">
                @{
                    if (DT == DialogTypes.Alert)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal()">Close</button>
                    }
                    else if (DT == DialogTypes.Prompt)
                    {
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal(true)">Yes</button>
                        <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal(false)">No</button>
                    }
                }
            </div>
        </div>
    </div>
</div>

<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>


@code {

    public enum DialogTypes
    {
        Alert = 0,
        Prompt
    }

    private DialogTypes DT = DialogTypes.Alert;
    private bool confirmed = false;
    public Guid Guid = Guid.NewGuid();
    public string ModalDisplay = "none;";
    public string ModalClass = "";
    public bool ShowBackdrop = false;

    public string Title { get; set; }
    public string Message { get; set; }

    private TaskCompletionSource<bool> _alertTaskCompletionSource = new();
    private Task<bool> _alertTask = Task.FromResult(true);

    private TaskCompletionSource _taskCompletionSource = new();
    private Task _task = Task.CompletedTask;

    public Task<bool> PromptAsync(string message, string title)
    {
        // Check if the modal is already running and exit if it is
        if (!_alertTask.IsCompleted || !_task.IsCompleted)
            return Task.FromResult(false);

        DT = DialogTypes.Prompt;
        Title = title;
        Message = message;
        ModalDisplay = "block;";
        ModalClass = "show";
        StateHasChanged();

        _alertTaskCompletionSource = new();
        _alertTask = _alertTaskCompletionSource.Task;

        return _alertTask;
    }

    public Task AlertAsync(string message, string title)
    {
        // Check if the modal is already running and exit if it is
        if (!_alertTask.IsCompleted || !_task.IsCompleted)
            return Task.CompletedTask;

        Title = title;
        Message = message;
        ModalDisplay = "block;";
        ModalClass = "show";
        StateHasChanged();

        _taskCompletionSource = new();
        _task = _taskCompletionSource.Task;

        return _alertTask;
    }

    public void CloseModal()
    {
        ModalClass = "";
        ModalDisplay = "none;";
        StateHasChanged();
        if (!_task.IsCompleted)
            _taskCompletionSource.SetResult();

    }

    public void CloseModal(bool result)
    {
        ModalClass = "";
        ModalDisplay = "none;";
        StateHasChanged();
        _alertTaskCompletionSource.SetResult(result);
    }

}

这里有一个测试页面来演示它的工作原理:

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<div>
    <button class="btn btn-primary" @onclick=this.OpenModal>Open Dialog</button>
</div>

<MyModal @ref=_modal />

<div class="bg-dark text-white m-2 p-2">
    <pre>Result = @_result</pre>

</div>

@code {
    private MyModal? _modal;
    private bool _result;

    private async Task OpenModal()
    {
        if (_modal is not null)
        {
            _result = await _modal.PromptAsync("Do You Really Want To", "Exit Check");
            // Do whatever you want with the result
        }
    }
}

评论

0赞 Single Step Debugger 6/14/2023
经过测试并有效。我刚刚从示例中清除了我的标记和消息中的一个小错误,因此我们有一个完整的组件包含您的解决方案:
0赞 Single Step Debugger 6/14/2023 #2

这是 MrC aka Shaun Curtis 解决方案,没有我对完整组件的错误标记: 固定标记:

<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay" aria-hidden="true" data-toggle="modal">
<div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
        <div class="modal-header blue-dlg">
            <p class="modal-title">@Title</p>
            @{
                if (DT == DialogTypes.Alert)
                {
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="() => CloseModal()">
                                        <span aria-hidden="true">&times;</span>
                                    </button>
                }
                else if (DT == DialogTypes.Prompt)
                {
                            <button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="() => CloseModal(false)">
                                        <span aria-hidden="true">
                                            &times;
                                        </span>
                                    </button>
                }
            }
        </div>
        @{
            if (DT == DialogTypes.Alert)
            {
                <div class="modal-body dlg-validation">
                    <p>@Message</p>
                </div>
            }
        }
        <div class="modal-footer justify-content-center">
            @{
                if (DT == DialogTypes.Alert)
                {
                                    <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => CloseModal()">Close</button>
                }
                else if (DT == DialogTypes.Prompt)
                {
                                    <button type="button" class="btn btn-primary" data-dismiss="modal" @onclick="() => CloseModal(true)">Yes</button>
                                    <button type="button" class="btn btn-primary" data-dismiss="modal" @onclick="() => CloseModal(false)">No</button>
                }
            }
        </div>
    </div>
</div>

和固定警报:

    public Task<bool> PromptAsync(string title)
{
    // Check if the modal is already running and exit if it is
    if (!_alertTask.IsCompleted || !_task.IsCompleted)
        return Task.FromResult(false);

    DT = DialogTypes.Prompt;
    Title = title;
    ModalDisplay = "block;";
    ModalClass = "show";
    StateHasChanged();

    _alertTaskCompletionSource = new();
    _alertTask = _alertTaskCompletionSource.Task;

    return _alertTask;
}

评论

1赞 MrC aka Shaun Curtis 6/14/2023
请随时修改我的答案和您的更正。这意味着有一个公认的答案。