反映跨序列化对象设置PropertyChanged事件

本文关键字:设置 PropertyChanged 事件 对象 序列化 | 更新日期: 2023-09-27 18:09:58

我有一个对象,它是通过一些XML的反序列化创建的。我使用Visual Studio的工具从供应商的XML模型生成XSD。然后使用XSD工具从它们那里获得类。我设置了XSD工具,使它生成的类为INotifyPropertyChanged。

现在我正试图在我的WPF应用程序的"选项卡"中显示此对象。每当有人做出改变时,我想要一个"肮脏"的指示。问题是,从生成的XSD生成类的这个对象并不是最漂亮的结构。此对象的显示不模仿其数据结构。我考虑创建显示对象(不使用MMVM ATM),并使用这些对象将我的更改绑定到对象,然后将这些更改作为数据对象持久化。我只需要跳出当前显示来做这个因为我现在只需要添加一个检查是否有编辑

我的想法是反映整个对象,并为我遇到的每个属性设置PropertyChanged事件(遍历对象和属性的图)。我的反思让我失望,我也可能犯了一些短视的错误。

下面是我目前为止写的代码:
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[] { }));
        }
    }

我想我遇到了Observable集合属性类型问题,因为当我遍历我的对象时,它抛出了一个异常。我也不知道这个对象结构是否有循环引用。

谁能帮我解决这段代码,这样我就可以遍历对象图了。现在我不太担心循环引用的可能性,但如果有一个解决方案可以防止这种情况出现,那将非常非常有帮助!

根据卡雷尔的回答,我创建了这个"助手"类:

    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);
            }
        }
    }
}

反映跨序列化对象设置PropertyChanged事件

保留一个已经为其注册了事件的属性(组件)列表,并使函数递归。并且可以直接将组件cast到INotifyPropertyChanged

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);
  }  
}