blazor 向模板化组件添加参数

blazor add parameters to templated component

我有一个 Blazor Popup,它采用模板来显示他的内容:

CustomPopup.razor

<Popup
    @bind-Visible="@CreatePopupVisible"
    HorizontalAlignment="HorizontalAlignment.Center"
    VerticalAlignment="VerticalAlignment.Center"
    ShowFooter="true"
    HeaderText="@("Create" + Label)">
    <BodyTemplate>
        @EditForm
    </BodyTemplate>
    <FooterContentTemplate>
    </FooterContentTemplate>
</Popup>

@code {
    [Parameter]
    public string? Label { get; set; }

    [Parameter]
    public RenderFragment EditForm { get; set; }

    bool CreatePopupVisible { get; set; }

}

我向这个组件传递了一个带有 2 个按钮的 EditForm,它采用一个函数来处理取消选项:

CustomEditForm.razor

<EditForm Model="Entity" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="d-flex flex-column">
        <InputNumber id="factory-id" class="mt-2 mb-2" @bind-Value="Entity.Id" />
        <InputText id="factory-businessname" class="mt-2 mb-2" @bind-Value="Entity.BusinessName" />
        <InputText id="factory-address" class="mt-2 mb-2" @bind-Value="Entity.Address" />
        <div class="d-flex flex-row">
            <button class="btn btn-primary mt-2 mb-2 flex-grow-1" type="submit">Modifica</button>
            <button @onclick="HandleCancel" class="btn btn-secondary mt-2 mb-2 flex-grow-1" type="submit">Annulla</button>
        </div>
    </div>
</EditForm>

@code {

    [Parameter]
    public Action HandleCancel { get; set; }
    

    [Parameter]
    public Factory Entity { get; set; }
    
    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");
    }
}

如果我像这样正常使用 EditForm:

SomeFile.razor

<CustomEditForm HandleCancel="()=>{}">

一切都很好,但是当我在模板化组件中使用它时,如何从 CustomPupup.razor 文件中向他传递一个函数?

我需要传递一个函数来在有人点击取消按钮时将 CreatePopupVisible 设置为 false

提前求助!

编辑

感谢您的帮助,但我认为我提供的信息不足,无法获得正确答案,我的错

所以,我希望能够正常调用 CustomEditForm 并传递父定义的函数来管理 HandleCancel,如下所示:

MainPage.razor

@page ...

<Grid @ref="Grid">
//the grid has a method that closes this CustomEditForm
    <Template>
        <CustomEditForm HandleCancel="() => Grid.CancelRowEdit()"/>
    </Template>
</Grid>

但我也想使用自己内部定义的函数关闭弹出窗口,如下所示:

AnotherPage.razor

<CustomPopup>
    <EditForm>
        <CustomEditForm Entity="new Factory()"/>
    </EditForm>
</CustomPopup>

在这种情况下,编辑表单应通过调用 CustomPopup 定义的方法来处理取消

由于您的问题中没有足够的代码作为答案的基础,我将使用一个非常简单的组件来演示您如何可以做您想做的事情。

这是我的“PopUp”模拟器。

@if (this.Visible)
{
    <h3>PopUp</h3>
    @this.ChildContent
}

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public bool Visible { get; set; }
}

然后是我的 CustomPopUp。请注意,我正在级联 this 并且有一个 public Close 方法。


<PopUp Visible="this.CreatePopupVisible">
    <CascadingValue Value=this>
    @this.ChildContent
    </CascadingValue>
</PopUp>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }

    bool CreatePopupVisible { get; set; }

    public void Show()
    {
        this.CreatePopupVisible = true;
    }

    public void Close()
    {
        this.CreatePopupVisible = false;
        this.StateHasChanged();
    }
}

接下来是我的 EditForm。请注意,我捕获了 CustomMyPopUp 的 Cascaded 实例。我的 Cancel 现在检查我们是否有级联值(我们在 PopUp 上下文中),如果有,则在弹出窗口上调用 Close。它还会检查 HandleCancel 上是否有已注册的委托,只有在有时才调用它。

<div class="m-2 p-5 bg-light">
<h3>EditForm</h3>
<div class="p-2 m-2">
<button class="btn btn-danger" @onclick="this.Cancel">Cancel</button>
</div>
</div>
@code {
    [CascadingParameter] private CustomPopUp? myPopUp { get; set; }
    [Parameter] public EventCallback<bool> HandleCancel { get; set; }

    public async Task Cancel()
    {
        if (this.myPopUp is not null)
            myPopUp.Close();
        if (this.HandleCancel.HasDelegate)
            await HandleCancel.InvokeAsync();
    }
}

我的页面终于要测试了:

@page "/PopUp"
<h3>CascadePage</h3>
<CustomPopUp @ref=this.myPopUp>
    <MyEditForm />
</CustomPopUp>

<div class="p-2 m-2">
<button class="btn btn-primary" @onclick="this.Show">Show</button>
</div>

@code {
    private CustomPopUp? myPopUp;

    public void Show()
    => this.myPopUp?.Show();
}

听起来您只是想将对内部方法的引用传递给 RenderFragment,您可以使用 RenderFragment<Action> 来做到这一点 - 因为 HandleCancel 期望 Action 它可以 invoke:

<Popup
    @bind-Visible="@CreatePopupVisible"
    HorizontalAlignment="HorizontalAlignment.Center"
    VerticalAlignment="VerticalAlignment.Center"
    ShowFooter="true"
    HeaderText="@("Create" + Label)">
    <BodyTemplate>
        @EditForm(ClosePopup)
    </BodyTemplate>
    <FooterContentTemplate>
    </FooterContentTemplate>
</Popup>
@code {
    [Parameter]
    public string? Label { get; set; }

    [Parameter]
    public RenderFragment<Action> EditForm { get; set; }

    bool CreatePopupVisible { get; set; }

    void ClosePopup() 
    {
        CreatePopupVisible = false;

        // Because this method will be called by some external code
        // You should tell this component to render:

        InvokeAsync(StateHasChanged);
    } 
}

要使用它,标记可以引用 EditForm RenderFragmentcontext,这是一个 Action

<CustomPopup>
    <EditForm>
        <CustomEditForm Entity="new Factory()" HandleCancel=@context/>
    </EditForm>
</CustomPopup>

Try it out