如何在 blazor 中使用 Titem 制作具有多项选择和通用性的 table?

how to make a table with multiple selection and generic, using Titem in blazor?

我想制作一个 table component,使用可重复使用的多选 Titem,我设法进行了多选,但无法制作 component reusable,有什么建议吗? 我有一个可重复使用的 table,它是我通过查看来自 Microsoft https://docs.microsoft.com/en-us/aspnet/core/blazor/components/templated-components?view=aspnetcore-5.0 的直接示例制作的 这是我的代码:

@page "/multiple"

<div class="table-responsive">

    <table class="table table-sm table-bordered table-hover">
        <thead class="thead-dark">
            <tr>
                <th>Name</th>
                <th>Age</th>
            </tr>
        </thead>
        <tbody>
            @if (valueList != null)
            {
                int count = valueList.Count;
                for (var i = 0; i < count; i++)
                {
                    int current = i; // don't use loop variable in binding
                    var values = valueList[current];

                    <tr class="@values.Class" @onclick="((e) => SelectItems(current, true))">
                        <td>@values.Name</td>
                        <td>@values.Age</td>
                    </tr>
                }
            }
        </tbody>
        <tfoot>

        </tfoot>
    </table>
</div>

<button type="button" class="btn btn-sm btn-info" @onclick="showSelected">Click</button>

<hr />
@if (events != null)
{
    <ul>
        @foreach (var evt in events)
        {
            <li>@evt</li>
        }
    </ul>
}

@code
{
    //Declare various lists and classes.
    private List<Value> valueList;
    private List<string> events = new List<string>();

    class Value
    {
        public string Name { get; set; }
        public string Age { get; set; }
        public string Class { get; set; }
    }

    //OnInitialized function to instantiated the valueList.
    protected override void OnInitialized()
    {
        valueList = new List<Value>();
        valueList.Add(new Value()
        {
            Name = "James",
            Age = "38"
        });
        valueList.Add(new Value()
        {
            Name = "John",
            Age = "32"
        });
    }

    //Function to set selected class on tr. Can multi-select or single via Toggle bool.
    void SelectItems(int index, bool toggle)
    {
        var item = valueList[index];

        //If toggle then allow multiple to be selected. If class already selected then clear.
        if (toggle)
        {
            if (item.Class == "selected")
            {
                item.Class = "";
            }
            else
            {
                item.Class = "selected";
            }
        }
        else
        {
            foreach (var value in valueList)
            {
                value.Class = "";
            }
            // set the value
            item.Class = "selected";
        }
    }

    //Function to show the selected items.
    void showSelected()
    {
        events.Clear();
        foreach (var value in valueList)
        {
            if (value.Class.Contains("selected"))
            {
                events.Add($"'{value.Name}' selected. With value: '{value.Age}'");
            };
        }
    }
}

这个table已经是一个可重复使用的组件了,我怎样才能让它成为多选table:

 <table class="@TableClass">
        <thead class="@TheadClass">
            <tr>
                @Cabecera
            </tr>
        </thead>
        <tbody>
            @foreach (var item in ItemList)
            {
                <tr>@Filas(item)</tr>
            }
        </tbody>
        <tfoot>
            <tr>
                @Pie
            </tr>
        </tfoot>
    </table>

@code{

  [Parameter] public string ClassTable { get; set; }
  [Parameter] public string ClassThead { get; set; }
  [Parameter] public RenderFragment Cabecera { get; set; }
  [Parameter] public RenderFragment Pie { get; set; }
  [Parameter] public RenderFragment<TItem> Filas { get; set; }
  [Parameter] public IEnumerable<TItem> Items { get; set; }      
  IEnumerable<TItem> ItemList { get; set; }

  protected override async Task OnInitializedAsync()
   {
      ItemList = Items;
   }
}

正如official document所说,模板化组件是通用类型的,那么在使用TableTemplated时,可以通过模板参数将数据从主页面传输到TableTemplate组件。

尝试使用以下代码:

TableTemplate.razor:

@typeparam TItem

<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr>@RowTemplate(item)</tr>
        }
    </tbody>
</table>

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

    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; }

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

Index.razor:这里我们为每个单元格添加onclick事件。

<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
        <th>Class</th>
    </TableHeader>
    <RowTemplate >
        <td @onclick="((e)=>SelectItems(pet.PetId, true))">@pet.PetId</td> 
        <td @onclick="((e)=>SelectItems(pet.PetId, true))">@pet.Name</td>
        <td @onclick="((e)=>SelectItems(pet.PetId, true))">@pet.Class</td>
    </RowTemplate>
</TableTemplate>
<button type="button" class="btn btn-sm btn-info" @onclick="showSelected">Click</button>

@code {
    private List<Pet> pets = new List<Pet>()
    {
            new Pet { PetId = 2, Name = "Mr. Bigglesworth"  },
            new Pet { PetId = 4, Name = "Salem Saberhagen" },
            new Pet { PetId = 7, Name = "K-9" }
    };
    private List<string> events = new List<string>();
    private class Pet
    {
        public int PetId { get; set; }
        public string Name { get; set; }
        public string Class { get; set; }
    }
    void SelectItems(int petId, bool toggle)
    {
        var item = pets.Find(c=>c.PetId ==petId);

        //If toggle then allow multiple to be selected. If class already selected then clear.
        if (toggle)
        {
            if (item.Class == "selected")
            {
                item.Class = "";
            }
            else
            {
                item.Class = "selected";
            }
        }
        else
        {
            foreach (var value in pets)
            {
                value.Class = "";
            }
            // set the value
            item.Class = "selected";
        }
    }
    //Function to show the selected items.
    void showSelected()
    {
        foreach (var value in pets)
        {
            if (value.Class!=null && value.Class.Contains("selected"))
            {
                events.Add($"'{value.Name}' selected. With value: '{value.Name}'");                
            };
        }
    }
}

结果如下: