模板Blazor组件

时间:2020-04-21 14:27:04

标签: c# templates components blazor

只需考虑使用模板化的blazor组件来制作CRUD样式的单页应用程序,该应用程序可以传入特定对象,因此我不必一遍又一遍地编写相同的样板代码。

例如,如下所示,可以使用RenderFragment对象将其部分模板化:

@typeparam TItem

<div>
    @if (AddObjectTemplate != null)
    {
        @AddObjectTemplate
    }
    else
    {
        <div style="float:left">
            <button class="btn btn-primary" @onclick="AddObject">Add Object</button>
        </div>
    }
</div>

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

    [Parameter]
    public IList<TItem> Items { get; set; }

}

但是,更进一步,我可能想要这样的东西:

<button class="btn btn-default" @onclick="@(() => EditObject(item.Id))">Edit</button>

protected void EditObject(int id)
{
    TItem cust = _itemServices.Details(id);
}

问题在于,上面对EditObject(item.Id)的调用目前无法解析为特定对象,因为它不知道什么是TItem。有没有一种方法可以在模板组件中使用每个对象必须实现的特定接口,或者有另一种方法可以做到这一点?

这个想法是让AddObject,EditObject,DeleteObject等基本上都做相同的事情,但是对象类型不同。

1 个答案:

答案 0 :(得分:1)

由于将IList<TItem>作为参数,因此该列表存在于该组件之外的组件结构的另一个级别。因此,最好将EventCallBack<T>属性用于Add,Edit和Delete方法,并在连接组件时设置实际方法。这使模板组件仅成为渲染对象,并使要完成的实际“工作”保持在需要完成工作的实际列表附近。

设置模板组件时,您可以尝试使用类似的方法,效果很好。

Templator.razor

@typeparam TItem

<h3>Templator</h3>

@foreach (var item in Items)
{

    @ItemTemplate(item)

    <button @onclick="@(() => EditItemCallBack.InvokeAsync(item))">Edit Item</button>
}

@code {

    [Parameter]
    public IList<TItem> Items { get; set; }

    [Parameter]
    public EventCallback<TItem> EditItemCallBack { get; set; }

    [Parameter]
    public RenderFragment<TItem> ItemTemplate
}

Container.Razor

<h3>Container</h3>

<Templator TItem="Customer" Items="Customers" EditItemCallBack="@EditCustomer">

    <ItemTemplate Context="Cust">
        <div>@Cust.Name</div>
    </ItemTemplate>

</Templator>

@code {

    public List<Customer> Customers { get; set; }

    void EditCustomer(Customer customer)
    {
        var customerId = customer.Id;

        //Do something here to update the customer

    }

}

Customer.cs

public class Customer
{
    public int Id { get; set; }

    public string Name { get; set; }

}

这里的要点如下:

  1. 实际的根列表以及在该列表上工作的方法都位于模板化组件之外,因此上述所有内容都处于相同的抽象级别和相同的代码块中。

  2. 模板组件将接收一个列表,一个用于指定列表项将为哪种类型的类型以及在每个项目上执行的方法回调。 (或一系列方法,可以使用相同的方法添加您认为合适的“添加”和“删除”方法)。它还会收到您在调用Container.razor文件中的代码时指定的<ItemTemplate>渲染片段。

  3. 模板项中的'foreach'确保每个TItem都为其自身的RenderFragment,按钮集和回调函数设置。

  4. 使用EventCallBack<TItem>作为参数意味着您为其分配了一个方法,该方法期望返回TItem的整个对象。 这很好,因为模板现在不在乎TItem是什么类型,只有模板能够调用以TItem作为参数的方法!处理任何TItem的实例现在是调用代码的责任,而您不必尝试限制通用类型TItem。 (我还没有在Blazor中做过运气,也许是将来的发行版)

关于如何呈现输入到其中的任何TItem,HERE文档对此进行了很好的解释。

希望这会有所帮助!