C# 过滤ICollectionView时性能较慢<;对象>;
在使用MVVM的WPF应用程序中,我查询数据库以获取客户端的ObservableCollection,创建ICollectionView并应用筛选函数 在usercontrol上,我将用于过滤器的文本绑定到文本框,将ICollectionView绑定到列表框 ICollectionView最初包含1104个客户端(仅ClientID和ClientName) 从数据库检索数据非常快。但是,列表框填充大约需要4秒钟 当我在过滤器中输入文本时,如果要返回的客户端数量较低,则列表框会相对较快地重新绘制。但是,如果我清除了文本框,则需要另外4秒来重新绘制 是我遗漏了什么,还是我的代码写得不是很好 谢谢你的建议/帮助 视图:C# 过滤ICollectionView时性能较慢<;对象>;,c#,wpf,performance,mvvm,data-binding,C#,Wpf,Performance,Mvvm,Data Binding,在使用MVVM的WPF应用程序中,我查询数据库以获取客户端的ObservableCollection,创建ICollectionView并应用筛选函数 在usercontrol上,我将用于过滤器的文本绑定到文本框,将ICollectionView绑定到列表框 ICollectionView最初包含1104个客户端(仅ClientID和ClientName) 从数据库检索数据非常快。但是,列表框填充大约需要4秒钟 当我在过滤器中输入文本时,如果要返回的客户端数量较低,则列表框会相对较快地重新绘制。
视图模型:
using ClientReports.Common.Infrastructure.Models;
using ClientReports.Common.Infrastructure.Services;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Data;
namespace ClientReports.Module.SchemeSelection.ViewModels
{
public class ClientsViewModel : BindableBase
{
private IClientService clientService;
public ClientsViewModel(){ }
public ClientsViewModel(IClientService clientService)
{
this.clientService = clientService;
Clients = new ObservableCollection<Client>();
GetClients().ContinueWith(x => { });
}
public ObservableCollection<Client> Clients { get; }
public ICollectionView ClientsFiltered { get; set; }
private string clientFilter;
public string Search
{
get => clientFilter;
set
{
clientFilter = value;
ClientsFiltered.Refresh();
RaisePropertyChanged("ClientsFiltered");
}
}
private bool Filter(Client client)
{
return Search == null
|| client.ClientName.IndexOf(Search, StringComparison.OrdinalIgnoreCase) != -1;
}
private async Task GetClients()
{
var clients = await clientService.GetAllAsync();
foreach (var client in clients)
{
Clients.Add(client);
}
ClientsFiltered = CollectionViewSource.GetDefaultView(Clients);
ClientsFiltered.Filter = new Predicate<object>(c => Filter(c as Client));
}
}
}
使用ClientReports.Common.Infrastructure.Models;
使用ClientReports.Common.Infrastructure.Services;
使用Prism.Mvvm;
使用制度;
使用System.Collections.ObjectModel;
使用系统组件模型;
使用System.Threading.Tasks;
使用System.Windows.Data;
命名空间ClientReports.Module.SchemeSelection.ViewModels
{
公共类ClientsViewModel:BindableBase
{
专用IClientService客户端服务;
public ClientsViewModel(){}
公共客户端视图模型(IClientService客户端服务)
{
this.clientService=clientService;
Clients=新的observeCollection();
GetClients().ContinueWith(x=>{});
}
公共ObservableCollection客户端{get;}
公共ICollectionView客户端过滤{get;set;}
私有字符串clientFilter;
公共字符串搜索
{
get=>clientFilter;
设置
{
clientFilter=值;
ClientsFiltered.Refresh();
RaisePropertyChanged(“客户过滤”);
}
}
专用布尔过滤器(客户端)
{
返回搜索==null
||client.ClientName.IndexOf(Search,StringComparison.OrdinalIgnoreCase)!=-1;
}
私有异步任务GetClients()
{
var clients=await clientService.GetAllAsync();
foreach(客户机中的var客户机)
{
客户。添加(客户);
}
ClientsFiltered=CollectionViewSource.GetDefaultView(客户端);
ClientsFiltered.Filter=新谓词(c=>Filter(c作为客户机));
}
}
}
填充ListBox可能需要4秒钟,因为未启用虚拟化,所以WPF必须创建1104个ListBoxItems(并在清除筛选器时重新创建它们)。默认情况下,ListBox启用了虚拟化,但有时您甚至可以在没有意识到的情况下禁用它。在您的示例中,ListBox位于垂直StackPanel中,这可能是导致这种行为的原因。您可以尝试用以下方式重写XAML:
<UserControl x:Class="ClientReports.Module.SchemeSelection.Views.Clients"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientReports.Module.SchemeSelection.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox materialDesign:HintAssist.Hint="Client Search"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding Search, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="0"/>
<ListBox ItemsSource="{Binding ClientsFiltered}"
DisplayMemberPath="ClientName"
Grid.Row="1" />
</Grid>
</UserControl>
如果没有帮助,您可以尝试设置列表框的固定高度,然后再次选中
如果这也没有帮助,请检查Microsoft关于虚拟化的文档,原因可能是:我在构造函数中偶然发现了这一行:
GetClients().ContinueWith(x=>{})代码>。别那么做。改为阅读:谢谢@ChristianMurschall。我已经接受了这一点,并根据这篇文章重写了代码。@ChristianMurschall,这没有帮助。没有任何解释来支持您的陈述,并且链接的文章对ContinueWith
.Hi@richarp没有任何引用,因为您使用的是CollectionView和您可能感兴趣的筛选设置筛选器、SortDescriptions或GroupDescriptions属性时;出现刷新。设置其中一个属性后,不必立即调用Refresh方法。有关如何延迟自动刷新的信息,请参阅延迟刷新。“来源:[link][/link]@DonBoitnott我同意我的评论缺乏解释。但由于构造函数中的异步操作不是OPs问题,我认为链接可能是“后文式”的。顺便说一句,他的代码在图3中的链接文章中有解释,不是吗?谢谢@Pavel。我一使用您的XAML,它就立即工作了。非常有用。
<UserControl x:Class="ClientReports.Module.SchemeSelection.Views.Clients"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientReports.Module.SchemeSelection.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox materialDesign:HintAssist.Hint="Client Search"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding Search, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="0"/>
<ListBox ItemsSource="{Binding ClientsFiltered}"
DisplayMemberPath="ClientName"
Grid.Row="1" />
</Grid>
</UserControl>