我怎样才能解决这个糟糕的WPF ListView SelectedItems性能?

这是我的代码(它在WPF ListView中搜索所有匹配项,然后选择所有匹配项):

public bool FindAll(LogFilter filter, bool matchCase) { lastLogFilter = filter; lastMatchCase = matchCase; MatchSearcher quickSearchSearcher = new MatchSearcher(filter, !matchCase); bool foundOnce = false; Stopwatch watch = new Stopwatch(); watch.Start(); var query = from x in listView.Items.Cast() where quickSearchSearcher.IsMatch(x, false) select x; watch.Stop(); Console.WriteLine("Elapsed milliseconds to search: {0}.", watch.ElapsedMilliseconds); if (query.Count() > 0) { foundOnce = true; listView.SelectedItems.Clear(); watch.Restart(); foreach (LogRecord record in query) { listView.SelectedItems.Add(record); } watch.Stop(); Console.WriteLine("Elapsed milliseconds to select: {0}.", watch.ElapsedMilliseconds); listView.ScrollIntoView(query.First()); } return foundOnce; } 

以下是10,000个ListView项目的结果:

 Elapsed milliseconds to search: 0. Elapsed milliseconds to select: 36385. 

所以,显然我的问题是循环:

 foreach (LogRecord record in query) { listView.SelectedItems.Add(record); } 

我觉得必须有更好的方法来添加到选定的项目列表,或至少阻止列表上的数据模板更新(或类似的东西),直到所有选定的项目都已设置。 尝试在WPF ListView中以编程方式选择多个项目时,有没有办法获得更好的性能?

您可以调用SetSelectedItems方法,而不是逐个将所SelectedItems添加到SelectedItems属性。 不幸的是,该方法受到保护,因此您必须创建一个派生的ListBox,使其公开可用:

 public class MyListView : ListView { public void SelectItems(IEnumerable items) { SetSelectedItems(items); } } 

好的。 你已经接受了这个问题的答案,但我还想展示一种不同的方法:

在此处输入图像描述

XAML:

                    

代码背后:

 public partial class ListViewSearch : Window { private ViewModel ViewModel; public ListViewSearch() { InitializeComponent(); DataContext = ViewModel = new ViewModel(); } private void FindAll_Click(object sender, RoutedEventArgs e) { ViewModel.Filter(); } } 

视图模型:

 public class ViewModel { public ViewModel() { Items = new ObservableCollection(RandomDataSource.GetRandomData()); Filters = new ObservableCollection(); Filters.Add(new DataFilter() { DisplayName = "First Name starting with A", FilterExpression = x => x.FirstName.ToLower().StartsWith("a") }); Filters.Add(new DataFilter() { DisplayName = "Last Name starting with E", FilterExpression = x => x.LastName.ToLower().StartsWith("e") }); } public ObservableCollection Items { get; private set; } public DataFilter SelectedFilter { get; set; } public ObservableCollection Filters { get; private set; } public void Filter() { if (SelectedFilter == null) return; foreach (var item in Items) item.IsSelected = SelectedFilter.FilterExpression(item); } } 

数据项:

 public class DataItem : INotifyPropertyChanged { private bool _isSelected; public bool IsSelected { get { return _isSelected; } set { _isSelected = value; OnPropertyChanged("IsSelected"); } } public string LastName { get; set; } public string FirstName { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } 

数据过滤:

 public class DataFilter { public Func FilterExpression { get; set; } public string DisplayName { get; set; } } 

随机数据源(只是一堆样板)

 public static class RandomDataSource { private static string TestData = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum"; private static List words; private static int maxword; private static Random random; public static List GetRandomData() { random = new Random(); words = TestData.Split(' ').ToList(); maxword = words.Count - 1; return Enumerable.Range(0, 10000) .Select(x => GetRandomItem()) .ToList(); } private static DataItem GetRandomItem() { return new DataItem() { LastName = words[random.Next(0, maxword)], FirstName = words[random.Next(0, maxword)], }; } } 

与传统的代码隐藏方法相比,此方法具有以下优点:

  • 它解耦了UI和逻辑。 您针对自己定义的类进行操作,而不是处理(有时是神秘且模糊的)WPF对象模型。
  • 由于您的代码实际上并不依赖于任何特定的UI元素类型,因此您可以将UI更改为“3D旋转粉红色大象”,它仍然有效。 它可以在不影响任何代码或逻辑的情况下实现视图的更多可定制性。
  • 它很容易重用(你可以创建一个SearchViewModel和一个DataFilter并在许多不同的实体类型上重用它们。
  • 它是可unit testing的。