C# 如何在不知道blazor组件的属性名称和类型的情况下过滤该组件中的泛型列表参数

C# 如何在不知道blazor组件的属性名称和类型的情况下过滤该组件中的泛型列表参数,c#,.net-core,blazor,blazor-server-side,blazor-webassembly,C#,.net Core,Blazor,Blazor Server Side,Blazor Webassembly,下面是一个无序列表,其中包含一个搜索输入,可在键入时过滤列表。一切都很完美: @page "/todolist" <input @bind-value="SearchTerm" @bind-value:event="oninput" /> <span class="text-muted ml-5"> Showing @FilteredToDos.Count out of @ToDo

下面是一个无序列表,其中包含一个搜索输入,可在键入时过滤列表。一切都很完美:

@page "/todolist"

<input @bind-value="SearchTerm" @bind-value:event="oninput" />

<span class="text-muted ml-5">
    Showing @FilteredToDos.Count out of @ToDoItems.Count
</span>

<h4 class="mt-4">To Do's</h4>
<ul>
    @foreach (var toDo in FilteredToDos)
    {
        <li>@toDo.Name</li>
    }
</ul>

@code {
    // Initialize SearchTerm to "" to prevent null's
    string SearchTerm { get; set; } = "";

    // Data
    class ToDoItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    List<ToDoItem> ToDoItems => new List<ToDoItem>
    {
        new ToDoItem {Id = 1, Name = "Garbage" },
        new ToDoItem {Id = 2, Name = "Dishes" },
        new ToDoItem {Id = 3, Name = "Wash clothes" },
        new ToDoItem {Id = 4, Name = "Water flowers" }
    };
    //filter
    List<ToDoItem> FilteredToDos => ToDoItems.Where(i => i.Name.ToLower().Contains(SearchTerm.ToLower())).ToList();
}
@page”/todolist
显示@FilteredToDos.Count out@ToDoItems.Count
要做的事
    @foreach(FilteredToDos中的变量toDo) {
  • @待办事项名称
  • }
@代码{ //将SearchTerm初始化为“”,以防止出现null 字符串搜索项{get;set;}=”“; //资料 类ToDoItem { 公共int Id{get;set;} 公共字符串名称{get;set;} } List ToDoItems=>新建列表 { 新ToDoItem{Id=1,Name=“垃圾”}, 新ToDoItem{Id=2,Name=“disks”}, 新ToDoItem{Id=3,Name=“洗衣服”}, 新ToDoItem{Id=4,Name=“Water flowers”} }; //滤器 List FilteredToDos=>ToDoItems.Where(i=>i.Name.ToLower().Contains(SearchTerm.ToLower()).ToList(); }
我将列表分为自己的组件(TodoComponent):

@typeparam-TItem
要做的事
    @foreach(toDo中的变量toDo) { @无序列表(toDo) }
@代码{ [参数] 公共列表TODO{get;set;} [参数] 公共RenderFragment无序列表{get;set;} 字符串搜索项{get;set;}=”“; List FilteredToDos=>Todos.Where(i=>i.Name.ToLower().Contains(SearchTerm.ToLower()).ToList(); }
我在这里调用blazor组件:

@page "/todo"

    <TodoComponent Todos="@ToDoItems">
        <UnorderedList>
            <li>ID: @context.Id Name: @context.Name </li>
        </UnorderedList>
    </TodoComponent>

@code {
    private List<ToDoItem> ToDoItems => new List<ToDoItem>
        {
            new ToDoItem {Id = 1, Name = "Garbage" },
            new ToDoItem {Id = 2, Name = "Dishes" },
            new ToDoItem {Id = 3, Name = "Wash clothes" },
            new ToDoItem {Id = 4, Name = "Water flowers" }
        };

    public class ToDoItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

}
@page”/todo
  • ID:@context.ID Name:@context.Name
  • @代码{ 私有列表ToDoItems=>新列表 { 新ToDoItem{Id=1,Name=“垃圾”}, 新ToDoItem{Id=2,Name=“disks”}, 新ToDoItem{Id=3,Name=“洗衣服”}, 新ToDoItem{Id=4,Name=“Water flowers”} }; 公共类待办事项 { 公共int Id{get;set;} 公共字符串名称{get;set;} } }

    列表显示良好,但我无法再过滤列表。我不想把过滤函数放在组件之外。基于组件内部的名称或ID进行过滤的最佳方式是什么?使用不同的数据结构而不是列表是否更好?

    向名为
    GetFilterData
    的组件添加一个参数属性,该组件是
    Func

    然后,您可以对每个项目调用
    GetFilterData
    ,以决定是否应该包含它

    将标准模板Blazor应用程序中的FetchData
    标记更改为以下内容:

        <table class="table">
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Temp. (C)</th>
                    <th>Temp. (F)</th>
                    <th>Summary</th>
                </tr>
            </thead>
            <tbody>
                <MyList Items=@forecasts GetFilterableText=@(item => $"{item.Date} {item.Summary} {item.TemperatureC} {item.TemperatureF}" )>
                    <tr>
                        <td>@context.Date.ToShortDateString()</td>
                        <td>@context.TemperatureC</td>
                        <td>@context.TemperatureF</td>
                        <td>@context.Summary</td>
                    </tr>
                </MyList>
            </tbody>
        </table>
    
    
    日期
    临时雇员(C)
    临时雇员(F)
    总结
    $“{item.Date}{item.Summary}{item.TemperatureC}{item.TemperatureF}”)>
    @context.Date.ToShortDateString()的
    @上下文温度
    @context.TemperatureF
    @背景.摘要
    
    然后将以下组件添加到应用程序中

    @typeparam TItem
    
    <input @bind=Filter @bind:event="oninput" />
    @foreach (TItem item in GetFilteredItems())
    {
        if (ChildContent == null)
        {
            <li>@item?.ToString()</li>
        }
        else
        {
            @ChildContent(item);
        }
    }
    
    @code {
            [Parameter]
            public IEnumerable<TItem> Items { get; set; }
    
            [Parameter]
            public Func<TItem, string> GetFilterableText { get; set; }
    
            [Parameter]
            public RenderFragment<TItem> ChildContent { get; set; }
    
        private string Filter;
        private static readonly Func<TItem, string> DefaultGetFilterableText =
            item => (item?.ToString() ?? "");
    
    
        private IEnumerable<TItem> GetFilteredItems()
        {
            Func<TItem, string> filterFunc = GetFilterableText ?? DefaultGetFilterableText;
            IEnumerable<TItem> result = (Items ?? Array.Empty<TItem>());
            if (!string.IsNullOrEmpty(Filter))
            {
                result = result
                    .Where(x =>
                        (GetFilterableText(x) ?? "")
                        .Contains(Filter, StringComparison.InvariantCultureIgnoreCase));
            }
            return result;
        }
    
    }
    
    @typeparam-TItem
    @foreach(GetFilteredItems()中的TItem项)
    {
    if(ChildContent==null)
    {
    
  • @项目?.ToString()
  • } 其他的 { @儿童内容(项目); } } @代码{ [参数] 公共IEnumerable项{get;set;} [参数] 公共函数GetFilterableText{get;set;} [参数] 公共RenderFragment ChildContent{get;set;} 私有字符串过滤器; 私有静态只读函数DefaultGetFilterableText= item=>(item?.ToString()??“”); 私有IEnumerable GetFilteredItems() { Func filterFunc=GetFilterableText??DefaultGetFilterableText; IEnumerable结果=(Items??Array.Empty()); 如果(!string.IsNullOrEmpty(筛选器)) { 结果=结果 .其中(x=> (GetFilterableText(x)??“”) .包含(筛选器、StringComparison.InvariantCultureIgnoreCase)); } 返回结果; } }

    您应该能够根据自己的需要对其进行调整。

    如果对TItem没有类型约束,您的ToDoComponent就无法了解“name”属性。您可以使用反射来查找适当的过滤器属性。但是,我认为数据不应该在BLAZOR中排序或过滤,并将一些排序查询参数传递给服务器。看看ODATA图书馆。哇,每天学习新东西!这很管用,谢谢你,这很管用。也许可以用类似的方式实现排序?
    @typeparam TItem
    
    <input @bind=Filter @bind:event="oninput" />
    @foreach (TItem item in GetFilteredItems())
    {
        if (ChildContent == null)
        {
            <li>@item?.ToString()</li>
        }
        else
        {
            @ChildContent(item);
        }
    }
    
    @code {
            [Parameter]
            public IEnumerable<TItem> Items { get; set; }
    
            [Parameter]
            public Func<TItem, string> GetFilterableText { get; set; }
    
            [Parameter]
            public RenderFragment<TItem> ChildContent { get; set; }
    
        private string Filter;
        private static readonly Func<TItem, string> DefaultGetFilterableText =
            item => (item?.ToString() ?? "");
    
    
        private IEnumerable<TItem> GetFilteredItems()
        {
            Func<TItem, string> filterFunc = GetFilterableText ?? DefaultGetFilterableText;
            IEnumerable<TItem> result = (Items ?? Array.Empty<TItem>());
            if (!string.IsNullOrEmpty(Filter))
            {
                result = result
                    .Where(x =>
                        (GetFilterableText(x) ?? "")
                        .Contains(Filter, StringComparison.InvariantCultureIgnoreCase));
            }
            return result;
        }
    
    }