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



下面是一个无序列表,带有一个搜索输入,可以在键入时过滤列表。一切都很完美:

@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();
}

我把这个列表分成了它自己的组件(TodoComponent(:

@typeparam TItem
<input @bind-value="SearchTerm" @bind-value:event="oninput" />
<h4 class="mt-4">To Do's</h4>
<ul>
@foreach (var toDo in Todos)
{
@UnorderedList(toDo)
}
</ul>
@code {
[Parameter]
public List<TItem> Todos { get; set; }
[Parameter]
public RenderFragment<TItem> UnorderedList { get; set; }
string SearchTerm { get; set; } = "";
List<TItem> 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; }
}
}

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

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

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

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

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

然后将以下组件添加到您的应用

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

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

相关内容

  • 没有找到相关文章

最新更新