如何仅为可见元素引发OnPropertyChanged?

时间:2011-12-22 08:56:25

标签: c# .net wpf mvvm

我有很大的网格。我想使用CheckBox“check / uncheck all”来检查/取消选中所有行。但它很慢,因为有很多OnPtopertyChanged事件的调用。如何仅为可见元素引发OnPropertyChanged事件?启用了行的虚拟化。

4 个答案:

答案 0 :(得分:1)

20000行很多:)

如果断开ItemsSource绑定,改变viewmodel中的列表并将itemssource设置为新的检查列表,会发生什么?

如果他们想要20000个,他们可以等待它;)

修改

如果您不更改您的itemssource,您必须为每个项目提高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}" />

但我不知道第二种方法是否更快,你应该测试它。

答案 1 :(得分:0)

处理此问题的一种方法是在ViewModel中拥有boolean IsVisible属性。如果IsVisible仅返回true,则您可以举起PropertyChanged事件。

答案 2 :(得分:0)

更新1我在创建了一个100K行的简单repro之后,它在我的低规格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>

答案 3 :(得分:0)

第一种方法:删除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 
}