Asynchronous Blazor Howto-查找winform MessageBox()函数

Asynchronous Blazor Howto-查找winform MessageBox()函数,asynchronous,events,async-await,blazor,Asynchronous,Events,Async Await,Blazor,我正在使用VS2019和Blazor服务器Net5。附带的Bootstrap4环境提供了模式对话框,我想从旧的Windows窗体复制一些类似MessageBox()的东西。这意味着您执行(在按钮点击事件中)类似 DialogResult x=[Wait]MessageBox[Async](“SomeMsg”,SomeButtons+SomeIcon) 在x中,您可以找到用户单击的选项(DialogResult.OK,Cancel,…) 因此,我发现了几个示例如何显示模型对话框本身,并将其作为组件

我正在使用VS2019和Blazor服务器Net5。附带的Bootstrap4环境提供了模式对话框,我想从旧的Windows窗体复制一些类似MessageBox()的东西。这意味着您执行(在按钮点击事件中)类似

DialogResult x=[Wait]MessageBox[Async](“SomeMsg”,SomeButtons+SomeIcon)

在x中,您可以找到用户单击的选项(DialogResult.OK,Cancel,…)

因此,我发现了几个示例如何显示模型对话框本身,并将其作为组件编写

public async Task<ModalResultType> ShowAsync(string title, string messagetext)
{
   Title = title;
   Message = messagetext;
   ShowMessageBox = true;
   StateHasChanged();
   //
   // Now I m at a loss... how to await here what the User did click???
   //
   return whatTheUserDidClick;
}

// Click event from button, called with the appropiate ModalResultType
//
public async Task OnButtonClicked(ModalResultType value)
{
   ShowMessageBox = false;
   //
   // Now I am at a  loss - how to pass the clicked value into the waiting context
   // of the UI above from and "complete" the awaiting ShowAsync();
   //
}
我有一个简单的组件MessageBox.razor

public enum ModalResultType { Closed = 0, OK = 1, Cancel = 2, }

@if (ShowMessageBox == true)
{
   <div class="modal fade show d-block" id="MessageBox" tabindex="-1"
      role="dialog" aria-hidden="true">
   .... and so forth ....
   <button type="button" class="close" data-dismiss="modal" aria-label="Close"
      @onclick="() => OnButtonClick(ModalResultType.Closed)">X</button>
   ... and so forth ...
   <button type="button" class="btn btn-primary" data-dismiss="modal"
      @onclick="() => OnButtonClick(ModalResultType.OK)">OK</button>
   <button type="button" class="btn btn-secondary" data-dismiss="modal"
      @onclick="() => OnButtonClick(ModalResultType.Cancel)">Cancel</button>
   .. and so forth ...
   </div>
}
我找到了一个模态对话框的示例,在这些对话框中,事件处理程序被绑定到要执行的操作上,比如删除记录。但这并不是我想要的——我需要将html特别绑定到我当时所在的页面或组件的细节。或者我需要提供一个回调函数,这将打破我目前的轨道;要设置ShowMessageBox标志,请从单击事件返回,然后在另一个方法中继续执行逻辑

所以问题是:我如何在事件处理程序中等待由其他UI事件触发的事件


我需要线程吗?我不这么认为。它应该可以通过任务、异步和仅等待来实现。但是,如何创建一个可等待的对象,“发出”完成或取消此类任务的信号?它在Blazor UI组件环境中工作。

我利用
System.Threading.SemaphoreSlim
类在
Modal.cs
中的
ValueTask OpenModal()
中实现了可期待的结果

using Microsoft.AspNetCore.Components;

public partial class ModalLauncher : ComponentBase
{
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public RenderFragment ModalContent { get; set; }

    public void ShowModal(RenderFragment renderFragment)
    {
        ModalContent = renderFragment;
        StateHasChanged();
    }

    public void CloseModal()
    {
        ModalContent = null;
        StateHasChanged();
    }
}
public class Modal<T> : ComponentBase
{
    [Parameter]
    public RenderFragment<ModalContext<T>> ChildContent { get; set; }

    [Parameter]
    public T Value { get; set; }

    [CascadingParameter]
    public ModalLauncher Launcher { get; set; }

    public async ValueTask<ModalResult<T>> OpenModal(T value)
    {
        var modalContext = new ModalContext<T> { Modal = this, Value = value };
        RenderFragment renderFragment = ChildContent.Invoke(modalContext);
        Launcher.ShowModal(renderFragment);
        await semaphore.WaitAsync();
        return new ModalResult<T> { ModalAction = modalAction, Value = value };
    }

    public void CancelModal() => CloseModal(ModalAction.Cancel);
    public void CloseModal() => CloseModal(ModalAction.Close);
    public void OkModal() => CloseModal(ModalAction.Ok);

    private void CloseModal(ModalAction action)
    {
        modalAction = action;
        Launcher.CloseModal();
        semaphore.Release();
    }

    private ModalAction modalAction;
    private SemaphoreSlim semaphore = new SemaphoreSlim(0, 1);
}

ModalLauncher.razor

<CascadingValue Value="this">
    @if (ModalContent is not null)
    {
        @ModalContent
    }
    @ChildContent
</CascadingValue>
把这个包装在你的布局上

@inherits LayoutComponentBase
<ModalLauncher>
    <div class="page">
        ...
    </div>
</ModalLauncher>
您还需要重写引导
.modal
类的一部分。将其放入
wwwroot\css\app.css

.modal {
    display: block;
}

这是每个Blazor组件框架的一个特性。这是一个简单的DIY。谢谢你——这让我有了一些见解。@PhilippOtt你可能想看看我一直在修补的这个:
public enum ModalAction
{
    Cancel,
    Close,
    Ok,
}

public class ModalContext<T>
{
    public T Value { get; set; }
    public Modal<T> Modal { get; set; }
}
public class ModalResult<T>
{
    public T Value { get; set; }
    public ModalAction ModalAction { get; set; }
}

public class SomeClass
{
    public int SomeValue { get; set; }
}

@page "/"

<button @onclick="@OpenSomeClassModal">Run Demo</button>

<Modal @ref="someClassModal" T="SomeClass">
    ...   
    <input type="number" @bind-value="@context.Value.SomeValue" />
    ...
    <button type="button" class="btn btn-secondary" @onclick="@context.Modal.CancelModal">Cancel</button>
    <button type="button" class="btn btn-primary" @onclick="@context.Modal.OkModal">Save changes</button>
    ...             
</Modal>

<Modal @ref="someStringModal" T="string">
    ...
    <p> @context.Value</p>
    ...
    <button type="button" class="btn btn-secondary" @onclick="@context.Modal.OkModal">Close</button>
    ...
</Modal>


@code {
    Modal<SomeClass> someClassModal;
    Modal<string> someStringModal;

    async Task OpenSomeClassModal()
    {
        var someClass = new SomeClass { SomeValue = 9 };
        var result1 = await someClassModal.OpenModal(someClass);
        var result2 = await someStringModal.OpenModal($"The value was set to {result1.Value.SomeValue}, you pressed {result1.ModalAction}");
    }
}
.modal {
    display: block;
}