Updating ObservableCollection Object Properties Using the INotifyPropertyChanged Method

Check to make sure my assumptions are correct.

I have an ObservableCollection class. I call the web service and get an array of devices. Then I enumerate the ObservableCollection and install each item on the corresponding device received from the web service. The devices I received have different property values ​​than the elements in the ObservableCollection, but PropertyChanged events do not fire.

I assume this is ByDesign and that in order to have an event with a PropertyChanged event, do I really have to list each property and set a value?

For example, in the following case, PropertyChanged events do not fire in any of the properties of the Device class.

ObservableCollection<Device> Items = new ObservableCollection<Device>(); Items = LoadItems(); List<Device> devices = GetDevices(); foreach (var item in Items) { var currentDevice = devices.Single(d1 => d1.ID == item.ID); item = currentDevice; } 

However, if I manually update each property, I have a business:

 ObservableCollection<Device> Items = new ObservableCollection<Device>(); Items = LoadItems(); List<Device> devices = GetDevices(); foreach (var item in Items) { var currentDevice = devices.Single(d1 => d1.ID == item.ID); item.Latitude = currentDevice.Latitude; item.Longitude= currentDevice.Longitude; } 

In the above case, both Latitude and Longitude trigger their events.

Since my class has many properties, is there a better way to do this than one by one?

+4
source share
4 answers

The Load method may be useful for this, so you do not rewrite the link, but set all the properties of the old object. Here is the general extension method that I just wrote that assigns all writable properties, it is very crude:

 public static class ExtensionMethods { public static void Load<T>(this T target, Type type, T source, bool deep) { foreach (PropertyInfo property in type.GetProperties()) { if (property.CanWrite && property.CanRead) { if (!deep || property.PropertyType.IsPrimitive || property.PropertyType == typeof(String)) { property.SetValue(target, property.GetValue(source, null), null); } else { object targetPropertyReference = property.GetValue(target, null); targetPropertyReference.Load(targetPropertyReference.GetType(), property.GetValue(source, null), deep); } } } } } 

Then you can call

 item.Load(item.GetType(), currentDevice, true); //false for shallow loading 

to assign all values ​​(if they are properties).

Edit: Made the method recursive to call Load for properties that do not have a primitive type or value type (or string). Probably in some cases still wrong.
You can also add bool deep to the method and control if it should load heavily, if necessary. (Just add || !deep to this long if statement)

Note. Of course, you can also rewrite the reference to the object and use reflection to raise the PropertyChanged event for all the various properties, if you prefer. In any case, you do not need to manually process each property.

Edit2: Since PropertyInfo.GetValue returns an object , my previous code did not load recursively, unfortunately, with this you need to explicitly pass the type, see revisions for the old version.

Edit3: For ways to do this work without a type reference, see this highlighted question I asked. However, this does not apply to other problems, such as circular references and properties that enumerate objects.

+1
source

In the first example, setting an item in a collection will result in the CollectionChanged event, not the PropertyChanged event of the individual item.

You can notify all properties by specifying an empty string in the PropertyChanged event. For instance:

 item.RaisePropertyChanged(""); 

where RaisePropertyChanged is a public method that raises the PropertyChanged event of the INotifyPropertyChanged implementation.

+3
source

I think you can overload the operator = and assign properties there. then PropertyChanged events will be generated, and you will still have the same syntax as in the first example.

0
source

The device class must implement the INotifyPropertyChanged interface. Then, for each fire property, the notify property changed the event as usual.

This will automatically change the notification of a property change.

0
source

Source: https://habr.com/ru/post/1338799/


All Articles