将参数传递给模态弹出窗口

问题描述 投票:0回答:2
modal-dialog blazor parameter-passing
2个回答
3
投票

这个问题有一个简单的答案,或者一个更长更全面的答案,演示如何构建一个“基本”模态对话框框架。这是后者。

您需要将 Modal DialogEditForm 分开。您应该能够在模态对话框中托管任何表单

首先,定义一个

IModalDialog
接口,这样我们就可以拥有多个模态对话框的实现 - 比如一个简单的干净的 Css 或 Bootstrap 。

public interface IModalDialog
{
    public ModalRequest ModalRequest { get; }
    public bool IsActive { get; }
    public bool Display { get; }
    public Task<ModalResult> ShowAsync<TModal>(ModalRequest modalRequest) where TModal : IComponent;
    public Task<bool> SwitchAsync<TModal>(ModalRequest modalRequest) where TModal : IComponent;
    public void Update(ModalRequest? modalRequest);
    public void Dismiss();
    public void Close(ModalResult result);
}

我们传入一个

ModalRequest

public record ModalRequest
{
    public IDictionary<string, object> Parameters { get; init; } = new Dictionary<string, object>();
    public object? InData { get; init; } = null;
}

然后回来

ModalResult

public class ModalResult
{
    public ModalResultType ResultType { get; private set; } = ModalResultType.NoSet;
    public object? Data { get; set; } = null;

    public static ModalResult OK() => new ModalResult() { ResultType = ModalResultType.OK };
    public static ModalResult Exit() => new ModalResult() { ResultType = ModalResultType.Exit };
    public static ModalResult Cancel() => new ModalResult() { ResultType = ModalResultType.Cancel };
    public static ModalResult OK(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.OK };
    public static ModalResult Exit(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.Exit };
    public static ModalResult Cancel(object data) => new ModalResult() { Data = data, ResultType = ModalResultType.Cancel };

    public enum ModalResultType { NoSet, OK, Cancel, Exit }
}

我们的基本实现 - ModalDialog.razor。它使用 TaskCompletionSource

async
上下文中运行。您可以通过调用
ShowAsync<TModal>
TModal
设置为要在表单中托管的组件并通过
ModalRequest
实例提供设置和数据来打开对话框。然后,您等待退出表单时设置为完成的提供
Task
。我们使用
DynamicComponent
来创建
TModal
。请注意,我们将 Modal 实例级联到托管组件。

@implements IModalDialog

@if (this.Display)
{
    <CascadingValue Value="(IModalDialog)this">
        <div class="base-modal-background" @onclick="OnBackClick">
            <div class="base-modal-content" @onclick:stopPropagation="true">
                <DynamicComponent Type=this.ModalContentType Parameters=this.ModalRequest.Parameters />
            </div>
        </div>
    </CascadingValue>
}

@code {
    [Parameter] public bool ExitOnBackGroundClick { get; set; } = false;

    public ModalRequest ModalRequest { get; private set; } = new ModalRequest();
    public object? InData { get; } = null;
    public bool Display { get; protected set; } = false;
    protected TaskCompletionSource<ModalResult> _ModalTask { get; set; } = new TaskCompletionSource<ModalResult>();
    protected Type? ModalContentType = null;

    public bool IsActive
        => this.ModalContentType is not null;

    public Task<ModalResult> ShowAsync<TModal>(ModalRequest modalRequest) where TModal : IComponent
    {
        this.ModalRequest = modalRequest;
        this.ModalContentType = typeof(TModal);
        this._ModalTask = new TaskCompletionSource<ModalResult>();
        this.Display = true;
        InvokeAsync(StateHasChanged);
        return this._ModalTask.Task;
    }

    public async Task<bool> SwitchAsync<TModal>(ModalRequest modalRequest) where TModal : IComponent
    {
        this.ModalRequest = modalRequest;
        this.ModalContentType = typeof(TModal);
        await InvokeAsync(StateHasChanged);
        return true;
    }

    public void Update(ModalRequest? modalRequest = null)
    {
        this.ModalRequest = modalRequest ?? this.ModalRequest;
        InvokeAsync(StateHasChanged);
    }

    private void OnBackClick(MouseEventArgs e)
    {
        if (ExitOnBackGroundClick)
            this.Close(ModalResult.Exit());
    }

    public async void Dismiss()
        => await this.Reset(ModalResult.Cancel());

    public async void Close(ModalResult result)
        => await this.Reset(result);

    private async Task Reset(ModalResult result)
    {
        _ = this._ModalTask.TrySetResult(ModalResult.Cancel());
        this.Display = false;
        this.ModalContentType = null;
        await InvokeAsync(StateHasChanged);
    }
}

它是组件 css - ModalDialog.razor.css

div.base-modal-background {
    display: block;
    position: fixed;
    z-index: 101; /* Sit on top */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

div.base-modal-content {
    background-color: #fefefe;
    margin: 10% auto;
    padding: 10px;
    border: 2px solid #888;
    width: 90%;
}

您的数据类别:

public class MyData
{
    public int Min { get; set; }
    public int Max { get; set; }
}

和表单 - MyForm.razor。这将捕获级联

IModalDialog
并与
IModalDialog
交互以获取任何提供的数据并关闭对话框。

<div class="modal-title border-bottom border-secondary">
    <h5>@this.Title</h5>
</div>

<div class="modal-body">
    <label class="form-label" for="Min">Enter Min [mm]</label>
    <input class="form-control" @bind=model.Min type="number">
    <label class="form-label" for="Max">Enter Max [mm]:</label>
    <input class="form-control" @bind=model.Max type="number">
</div>
<div class="modal-footer">
    <button type="button" class="btn btn-primary" @onclick="() => Done()">Done</button>
</div>


@code {
    private MyData model = new MyData();
    [Parameter] public string Title { get; set; } = "I Need a Title!";
    [CascadingParameter] private IModalDialog? modalDialog { get; set; }

    private ModalRequest modalRequest 
        => modalDialog?.ModalRequest ?? new ModalRequest();

    protected override void OnInitialized()
    {
        if (modalDialog is null)
            throw new NullReferenceException("You must cascade a IModalDialog to use this Form");

        model = (MyData)(modalDialog?.ModalRequest.InData ?? new MyData());
    }

    private void Done()
        => modalDialog?.Close(ModalResult.OK(model));
}

最后是演示页面。它托管

ModalDialog
组件并与其交互以打开对话框。

@page "/"

<PageTitle>Modal Dialog Demo</PageTitle>

<div class="m-2 b-2">
    <button class="btn btn-primary" @onclick=OpenDialog1>Edit Model 1</button>
</div>

<div class="alert alert-primary">
    <strong>Model 1</strong> Min: @this.model1.Min Max: @this.model1.Max
</div>

<div class="m-2 b-2">
    <button class="btn btn-dark" @onclick=OpenDialog2>Edit Model 2</button>
</div>

<div class="alert alert-dark">
    <strong>Model 2</strong> Min: @this.model2.Min Max: @this.model2.Max
</div>

<ModalDialog @ref=modalDialog ExitOnBackGroundClick=false />
@code {
    private MyData model1 = new MyData { Max = 20, Min = -10 };
    private MyData model2 = new MyData { Max = 50, Min = -50 };

    private IModalDialog? modalDialog;

    private async Task OpenDialog1()
    {
        var parameters = new Dictionary<string, object> { { "Title", "Modal Form 1" } };
        var request = new ModalRequest { InData = this.model1, Parameters = parameters };
        if (this.modalDialog is not null)
            await modalDialog.ShowAsync<MyForm>(request);
            // This won't complete until the dialog closes and the Task is complete.
            // We can use any return data at this point 
            // and this component will render as part of the ComponentBase UI event handling code.
    }

    private async Task OpenDialog2()
    {
        var parameters = new Dictionary<string, object> { { "Title", "Modal Form 2" } };
        var request = new ModalRequest { InData = this.model2 };
        if (this.modalDialog is not null)
            await modalDialog.ShowAsync<MyForm>(request);
    }
}

这是其中一个对话框的屏幕截图:

enter image description here

代码暂时放在这里 - https://github.com/ShaunCurtis/SO73617831


0
投票

我知道这已经有几年了,但我喜欢你在这里所做的概念。我在使用示例时注意到的一件事是 InData 被修改,这在某些情况下可能不是所需的结果。我知道这可以在派生对话框中处理。我还注意到上面示例中的 Reset(ModelResult result) 始终返回 ModalResult.Cancel。那应该是结果参数吗?由于您的临时存储库已消失,我看不到您是否进行了其他更改。

© www.soinside.com 2019 - 2024. All rights reserved.