ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

前端 未结 18 2690
一生所求
一生所求 2020-11-22 02:06

Does anyone know why this code doesn\'t work:

public class CollectionViewModel : ViewModelBase {  
    public ObservableCollection Con         


        
相关标签:
18条回答
  • 2020-11-22 02:52

    Here's an extension method for the above solution...

    public static TrulyObservableCollection<T> ToTrulyObservableCollection<T>(this List<T> list)
         where T : INotifyPropertyChanged
    {
        var newList = new TrulyObservableCollection<T>();
    
        if (list != null)
        {
            list.ForEach(o => newList.Add(o));
        }
    
        return newList;
    }  
    
    0 讨论(0)
  • 2020-11-22 02:53

    I try this solution, but only works for me like a RaisePropertyChange("SourceGroupeGridView") when collection changed, that fired for each item add or changed.

    The problem is in:

    public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
         NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
        OnCollectionChanged(args);
    }
    

    NotifyCollectionChangedAction.Reset this action make a complete rebind of all items in groupedgrid, is equivalent at RaisePropertyChanged. When you use it all groups of gridview refreshed.

    IF you, only want to refresh in UI the group of the new item, you don't use Reset action, you will need simulate a Add action in itemproperty with something like this:

    void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {         
        var index = this.IndexOf((T)sender);
    
        this.RemoveAt(index);
        this.Insert(index, (T)sender);
    
        var a = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, sender);
        OnCollectionChanged(a);
    }
    

    Sorry by my english, and thanks for the base code :), I hope this helps someone ^_^

    Enjoi!!

    0 讨论(0)
  • 2020-11-22 02:54

    Simple solution for standard observablecollection that I've used:

    DO NOT ADD to your property OR CHANGE it's inner items DIRECTLY, instead, create some temp collection like this

    ObservableCollection<EntityViewModel> tmpList= new ObservableCollection<EntityViewModel>();
    

    and add items or make changes to tmpList,

    tmpList.Add(new EntityViewModel(){IsRowChecked=false}); //Example
    tmpList[0].IsRowChecked= true; //Example
    ...
    

    then pass it to your actual property by assignment.

    ContentList=tmpList;
    

    this will change whole property which causes notice the INotifyPropertyChanged as you need.

    0 讨论(0)
  • 2020-11-22 02:56

    To Trigger OnChange in ObservableCollection List

    1. Get index of selected Item
    2. Remove the item from the Parent
    3. Add the item at same index in parent

    Example:

    int index = NotificationDetails.IndexOf(notificationDetails);
    NotificationDetails.Remove(notificationDetails);
    NotificationDetails.Insert(index, notificationDetails);
    
    0 讨论(0)
  • 2020-11-22 02:57

    Simple solution in 2 lines of code. Just use the copy constructor. No need to write TrulyObservableCollection etc.

    Example:

            speakers.list[0].Status = "offline";
            speakers.list[0] = new Speaker(speakers.list[0]);
    

    Another method without copy constructor. You can use serialization.

            speakers.list[0].Status = "offline";
            //speakers.list[0] = new Speaker(speakers.list[0]);
            var tmp  = JsonConvert.SerializeObject(speakers.list[0]);
            var tmp2 = JsonConvert.DeserializeObject<Speaker>(tmp);
            speakers.list[0] = tmp2;
    
    0 讨论(0)
  • 2020-11-22 03:01

    Added to TruelyObservableCollection event "ItemPropertyChanged":

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel; // ObservableCollection
    using System.ComponentModel; // INotifyPropertyChanged
    using System.Collections.Specialized; // NotifyCollectionChangedEventHandler
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ObservableCollectionTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                // ATTN: Please note it's a "TrulyObservableCollection" that's instantiated. Otherwise, "Trades[0].Qty = 999" will NOT trigger event handler "Trades_CollectionChanged" in main.
                // REF: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes
                TrulyObservableCollection<Trade> Trades = new TrulyObservableCollection<Trade>();
                Trades.Add(new Trade { Symbol = "APPL", Qty = 123 });
                Trades.Add(new Trade { Symbol = "IBM", Qty = 456});
                Trades.Add(new Trade { Symbol = "CSCO", Qty = 789 });
    
                Trades.CollectionChanged += Trades_CollectionChanged;
                Trades.ItemPropertyChanged += PropertyChangedHandler;
                Trades.RemoveAt(2);
    
                Trades[0].Qty = 999;
    
                Console.WriteLine("Hit any key to exit");
                Console.ReadLine();
    
                return;
            }
    
            static void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine(DateTime.Now.ToString() + ", Property changed: " + e.PropertyName + ", Symbol: " + ((Trade) sender).Symbol + ", Qty: " + ((Trade) sender).Qty);
                return;
            }
    
            static void Trades_CollectionChanged(object sender, EventArgs e)
            {
                Console.WriteLine(DateTime.Now.ToString() + ", Collection changed");
                return;
            }
        }
    
        #region TrulyObservableCollection
        public class TrulyObservableCollection<T> : ObservableCollection<T>
            where T : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler ItemPropertyChanged;
    
            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);
    
                if (ItemPropertyChanged != null)
                {
                    ItemPropertyChanged(sender, e);
                }
            }
        }
        #endregion
    
        #region Sample entity
        class Trade : INotifyPropertyChanged
        {
            protected string _Symbol;
            protected int _Qty = 0;
            protected DateTime _OrderPlaced = DateTime.Now;
    
            public DateTime OrderPlaced
            {
                get { return _OrderPlaced; }
            }
    
            public string Symbol
            {
                get
                {
                    return _Symbol;
                }
                set
                {
                    _Symbol = value;
                    NotifyPropertyChanged("Symbol");
                }
            }
    
            public int Qty
            {
                get
                {
                    return _Qty;
                }
                set
                {
                    _Qty = value;
                    NotifyPropertyChanged("Qty");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged(String propertyName = "")
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    #endregion
    }
    
    0 讨论(0)
提交回复
热议问题