项目更改时通知ObservableCollection

Pan*_*oul 39 c# collections wpf observablecollection inotifypropertychanged

我在这个链接上找到了

ObservableCollection没有注意到它中的Item何时发生变化(即使使用INotifyPropertyChanged)

一些通知Observablecollection项目已更改的技术.这个链接中的TrulyObservableCollection似乎正是我正在寻找的.

public class TrulyObservableCollection<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
    public TrulyObservableCollection()
    : base()
    {
        CollectionChanged += new NotifyCollectionChangedEventHandler(TrulyObservableCollection_CollectionChanged);
    }

    void TrulyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                (item as INotifyPropertyChanged).PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
            }
        }
    }

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyCollectionChangedEventArgs a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
        OnCollectionChanged(a);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我尝试使用它时,我没有收到有关该集合的通知.我不知道如何在我的C#代码中正确实现它:

XAML:

    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding MyItemsSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Binding="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        </DataGrid.Columns>
    </DataGrid>
Run Code Online (Sandbox Code Playgroud)

ViewModel:

public class MyViewModel : ViewModelBase
{
    private TrulyObservableCollection<MyType> myItemsSource;
    public TrulyObservableCollection<MyType> MyItemsSource
    {
        get { return myItemsSource; }
        set 
        { 
            myItemsSource = value; 
            // Code to trig on item change...
            RaisePropertyChangedEvent("MyItemsSource");
        }
    }

    public MyViewModel()
    {
        MyItemsSource = new TrulyObservableCollection<MyType>()
        { 
            new MyType() { MyProperty = false },
            new MyType() { MyProperty = true },
            new MyType() { MyProperty = false }
        };
    }
}

public class MyType : ViewModelBase
{
    private bool myProperty;
    public bool MyProperty
    {
        get { return myProperty; }
        set 
        {
            myProperty = value;
            RaisePropertyChangedEvent("MyProperty");
        }
    }
}

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
            PropertyChanged(this, e);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行程序时,我将3复选框设置为false,true,false,如属性初始化.但是当我改变其中一个ckeckbox的状态时,程序会通过item_PropertyChanged但从不在MyItemsSource属性代码中.

Rac*_*hel 81

您评论过的位置// Code to trig on item change...仅在集合对象发生更改时触发,例如当它设置为新对象或设置为null时.

使用您当前的TrulyObservableCollection实现,要处理集合中属性更改的事件,请注册CollectionChanged事件MyItemsSource

public MyViewModel()
{
    MyItemsSource = new TrulyObservableCollection<MyType>();
    MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged;

    MyItemsSource.Add(new MyType() { MyProperty = false });
    MyItemsSource.Add(new MyType() { MyProperty = true});
    MyItemsSource.Add(new MyType() { MyProperty = false });
}


void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // Handle here
}
Run Code Online (Sandbox Code Playgroud)

我个人真的不喜欢这个实现.您正在提出一个CollectionChanged事件,表示整个集合已经重置,只要房产发生变化.当然,它会在集合中的项目发生变化时随时更新UI,但我发现性能不佳,并且它似乎无法识别哪些属性发生了变化,这是关键信息之一在做某事时我通常需要PropertyChanged.

我更喜欢使用常规ObservableCollection,只是将PropertyChanged事件连接到它的项目上CollectionChanged.如果您的UI正确绑定到其中的项目,则ObservableCollection当集合中项目的属性发生更改时,您无需告知UI更新.

public MyViewModel()
{
    MyItemsSource = new ObservableCollection<MyType>();
    MyItemsSource.CollectionChanged += MyItemsSource_CollectionChanged;

    MyItemsSource.Add(new MyType() { MyProperty = false });
    MyItemsSource.Add(new MyType() { MyProperty = true});
    MyItemsSource.Add(new MyType() { MyProperty = false });
}

void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
        foreach(MyType item in e.NewItems)
            item.PropertyChanged += MyType_PropertyChanged;

    if (e.OldItems != null)
        foreach(MyType item in e.OldItems)
            item.PropertyChanged -= MyType_PropertyChanged;
}

void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "MyProperty")
        DoWork();
}
Run Code Online (Sandbox Code Playgroud)

  • @FrankLiu只有在集合本身发生变化时才会触发"ObservableCollection.CollectionChanged" - 要么更改新集合,要么添加新项目,要么删除项目.当集合中的项触发"PropertyChange"通知时,它不会*触发.这里的代码将一个`PropertyChanged`事件处理程序连接到每个项目,以便在它的`PropertyChanged`被触发时触发`CollectionChanged` (4认同)
  • 如果您将XAML绑定直接绑定到项目本身而不是项目上的属性,则此方法无效.在我的情况下(如果你参考他的例子),更改XAML中的一行看起来像这样:`<DataGridCheckBoxColumn Binding ="{Binding}"/>`任何人都有这种情况的解决方案? (3认同)

小智 9

我通过使用静态Action解决了这种情况


public class CatalogoModel 
{
    private String _Id;
    private String _Descripcion;
    private Boolean _IsChecked;

    public String Id
    {
        get { return _Id; }
        set { _Id = value; }
    }
    public String Descripcion
    {
        get { return _Descripcion; }
        set { _Descripcion = value; }
    }
    public Boolean IsChecked
    {
        get { return _IsChecked; }
        set
        {
           _IsChecked = value;
            NotifyPropertyChanged("IsChecked");
            OnItemChecked.Invoke();
        }
    }

    public static Action OnItemChecked;
} 

public class ReglaViewModel : ViewModelBase
{
    private ObservableCollection<CatalogoModel> _origenes;

    CatalogoModel.OnItemChecked = () =>
            {
                var x = Origenes.Count;  //Entra cada vez que cambia algo en _origenes
            };
}
Run Code Online (Sandbox Code Playgroud)


Mal*_*ick 5

一个简单的解决方案是使用BindingList<T>而不是ObservableCollection<T>. 事实上,BindingList 中继项更改通知。因此,对于绑定列表,如果项目实现了接口,INotifyPropertyChanged那么您可以使用ListChanged 事件简单地获取通知。

另请参阅SO 答案。


归档时间:

查看次数:

118087 次

最近记录:

5 年,9 月 前