Reflected through a serialized object to set the PropertyChanged event

I have an object that is created by deserializing some XML. I used the Visual Studio tool to generate XSD from the provider XML layout. Then, using the XSD tool, I got classes from them. I installed the XSD tool so that the generated classes are INotifyPropertyChanged.

Now I am trying to display this object in a β€œtab” in my WPF application. I want a dirty indicator whenever someone makes a change. The problem is that this object, being generated by classes from the generated XSD, is not the most beautiful structure. The display for this object does not mimic the data structure. I was thinking about creating display objects (without using ATM MMVMs) and using those that bind my changes and then store these changes in the object as a data object. I would just throw away my current screen to do this, since now I just add a check if there are changes.

My thought is to flip the object and set the PropertyChanged event for each property that I come across (going through the graph of objects and properties). My reflection fu fails, and I also probably make some short-sighted mistakes.

Here is the code that I have written so far:

void SetupPropertyChanged(INotifyPropertyChanged component) { component.PropertyChanged += CAMConfig_PropertyChanged; Type componentType = component.GetType(); foreach (PropertyInfo info in componentType.GetProperties()) { Type[] types = info.PropertyType.FindInterfaces((a, b) => { return a.ToString() == b.ToString(); }, typeof(INotifyPropertyChanged)); bool isINotify = types.Contains(typeof(INotifyPropertyChanged)); if (isINotify) this.SetupPropertyChanged((INotifyPropertyChanged)info.GetValue(component, new object[] { })); } } 

I think I am facing Observable property types, as it throws an exception when I move my object. It also just struck me that I did not know if this object structure would have circular references.

Can someone help me develop this code so that I can cross the graph of objects. Right now I'm not too concerned about the possibility of circular links, but if a solution appears that will prevent this from happening, it will be very, very helpful!

Based on Karel's answer, I created this helper class:

  public static class NotifyPropertyChangedHelper { public delegate void ChangeOccuredHandler(object sender); public static void SetupPropertyChanged(INotifyPropertyChanged component, ChangeOccuredHandler changedHandler) { SetupPropertyChanged(new List<object>(), component, changedHandler); } static void SetupPropertyChanged(IList<object> closed, INotifyPropertyChanged component, ChangeOccuredHandler changedHandler) { if (closed.Contains(component)) return; // event was already registered closed.Add(component); //adds the property that is to be processed //sets the property changed event if the property isn't a collection if (!(component is INotifyCollectionChanged)) component.PropertyChanged += (sender, e) => { changedHandler(sender); }; /* * If the component is an enumerable there are two steps. First check to see if it supports the INotifyCollectionChanged event. * If it supports it add and handler on to this object to support notification. Next iterate through the collection of objects * to add hook up their PropertyChangedEvent. * * If the component isn't a collection then iterate through its properties and attach the changed handler to the properties. */ if (component is IEnumerable<object>) { if (component is INotifyCollectionChanged) { //((INotifyCollectionChanged)component).CollectionChanged += collectionHandler; ((INotifyCollectionChanged)component).CollectionChanged += (sender, e) => { changedHandler(sender); }; } foreach (object obj in component as IEnumerable<object>) { if (obj is INotifyPropertyChanged) SetupPropertyChanged(closed, (INotifyPropertyChanged)obj, changedHandler); } } else { foreach (PropertyInfo info in component.GetType().GetProperties()) { var propertyValue = info.GetValue(component, new object[] { }); var inpc = propertyValue as INotifyPropertyChanged; if (inpc == null) continue; SetupPropertyChanged(closed, inpc, changedHandler); } } } } 
+4
source share
1 answer

Save the list of properties (components) for which you have already registered the event, and make your function recursive. And you can directly pass the INotifyPropertyChanged component.

 void SetupPropertyChanged(IList<object> closed, INotifyPropertyChanged component) { if(closed.Contains(component)) return; // event was already registered closed.Add(component); component.PropertyChanged += CAMConfig_PropertyChanged; foreach (PropertyInfo info in componentType.GetProperties()) { var propertyValue = info.GetValue(component, new object[] { }); var inpc = propertyValue as INotifyPropertyChanged; if(inpc == null) continue; this.SetupPropertyChanged(closed, inpc); } } 
+3
source

All Articles