如何仅对可见元素引发OnPropertyChanged
本文关键字:OnPropertyChanged 元素 何仅 | 更新日期: 2023-09-27 18:18:30
我有一个非常大的网格。我想使用复选框"选中/取消选中所有",这将选中/取消选中所有行。但是它非常慢,因为有很多调用OnPtopertyChanged事件。我如何提高OnPropertyChanged事件仅为可见的元素?
20000行太多了:)
如果断开ItemsSource绑定,改变视图模型中的列表并将ItemsSource设置为新的选中列表,会发生什么?
否则,如果他们想要20000行,他们可以等待;)
编辑如果你不改变你的itemssource,你必须为每个item触发propertychanged,否则你不会看到改变。
另一种方法是将绑定设置为null或new List
this.MyGridItemsViewModelProperty = new List();//"disconnect" the binding to the grid for the all check/uncheck
然后用check/uncheck改变你的真实列表,并将其设置为网格ItemsSource
this.MyGridItemsViewModelProperty = myupdatelist;
网格 <Grid ItemsSource="{Binding MyGridItemsViewModelProperty}" />
但是我不知道第二种方法是否更快,你应该测试一下
处理这个问题的一种方法是在ViewModel中有一个boolean IsVisible
属性。如果IsVisible
只返回true
,则可以引发PropertyChanged
事件。
更新1我创建了一个简单的复制与100K行,它在我的低规格PC上飞行,你可以检查它在你的,并确认它是否足够快?项目名称为GroupSelect
,然后只需复制/过去的东西到主窗口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace GroupSelect
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded +=
(o, e) =>
{
this.DataContext =
new Model(100000);
};
}
}
public class Model : INotifyPropertyChanged
{
private bool? isAllSelected = null;
public Model(int itemCount)
{
this.Items =
Enumerable.Range(1, itemCount).Select(t =>
new Item(this)
{
Name = "n_" + t.ToString()
}).ToList();
this.IsAllSelected = false;
}
public List<Item> Items
{
get;
private set;
}
public bool? IsAllSelected
{
get
{
return this.isAllSelected;
}
set
{
if (this.IsAllSelected != value)
{
this.IsBatchUpdate = true; // updating
this.isAllSelected = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this,
new PropertyChangedEventArgs("IsAllSelected"));
}
//
if (this.IsAllSelected.HasValue)
{
foreach (Item i in this.Items)
{
i.IsSelected = value.Value;
}
}
this.IsBatchUpdate = false; // updating
}
}
}
public bool IsBatchUpdate
{
get;
private set;
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Item: INotifyPropertyChanged
{
private bool isSelected = false;
public Item(Model model)
{
this.Model = model;
}
public Model Model
{
get;
private set;
}
public string Name
{
get;
set;
}
public bool IsSelected
{
get
{
return this.isSelected;
}
set
{
if (this.IsSelected != value)
{
this.isSelected = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this,
new PropertyChangedEventArgs("IsSelected"));
}
if (!this.Model.IsBatchUpdate)
{
this.Model.IsAllSelected = null;
}
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
标记:
<Window x:Class="GroupSelect.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GroupSelect"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="g" AutoGenerateColumns="False"
ItemsSource="{Binding Path='Items'}">
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}">
<DataGridCheckBoxColumn.HeaderTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center"
DataContext="{Binding Path=DataContext,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
IsChecked="{Binding Path=IsAllSelected, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridCheckBoxColumn.HeaderTemplate>
</DataGridCheckBoxColumn>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
第一种方法:删除OnPropertyChanged的引发并添加dataGrid.Items.Refresh();
第二种方法:静默更改属性,然后
var rows = grid.FindChildren<DataGridRowsPresenter>().First() as DependencyObject;
int count = VisualTreeHelper.GetChildrenCount(rows);
for (int i = 0; i < count; i++)
{
DataGridRow row = VisualTreeHelper.GetChild(rows, i) as DataGridRow;
(row.DataContext as IViewModel).Refresh();//Refresh invokes OnPropertyChanged
}