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;
}
}