如何从 INotifyPropertyChanged PropertyChanged 事件的发送者对象获取属性名称

发布于 2024-09-30 06:53:23 字数 9096 浏览 7 评论 0原文

我有一个 DependencyObject 基类,其中有一个方法接受对象、获取属性,并且对于属于实现 INotifyPropertyChanged 的​​类型的每个属性,我添加一个新的 PropertyChangedEventHandler。现在,在处理程序方法中,它获取对象“sender”的参数和PropertyChangedEventArgs“e”。我的问题是,如果 sender 是实现 INotifyPropertyChanged 的​​类型的属性,有谁知道如何动态获取属性名称。

这是我正在处理的内容:

public class BaseDependencyObject : DependencyObject, INotifyPropertyChanged
{
    public BaseDependencyObject()
    {

    }

    protected void SetValues(Object thisObject, Object entity)
    {
        try
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var value = property.GetValue(entity, null);
                var valueIsEntity = value is System.ServiceModel.DomainServices.Client.Entity;
                var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name);

                if (thisObjectsProperty != null && value != null)
                {
                    if (valueIsEntity)
                    {
                        if (thisObjectsProperty.PropertyType.GetInterface("INotifyPropertyChanged", true) != null)
                        {
                            var propertyInstance = Activator.CreateInstance(thisObjectsProperty.PropertyType);

                            ((INotifyPropertyChanged)propertyInstance).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                        }

                        SetValues(thisObjectsProperty, value);
                    }

                    else if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null
                        && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0)
                    {
                        Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0];

                        var observableCollection = Activator.CreateInstance(thisObjectsProperty.PropertyType) as IList;

                        if (observableCollection is INotifyCollectionChanged)
                            ((INotifyCollectionChanged)observableCollection).CollectionChanged += this.Object_CollectionChanged;

                        if (observableCollection is INotifyPropertyChanged)
                            ((INotifyPropertyChanged)observableCollection).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);

                        foreach (var item in (IEnumerable)value)
                        {
                            var newItem = Activator.CreateInstance(genericType);

                            if (newItem != null)
                            {
                                SetValues(newItem, item);
                                observableCollection.Add(newItem);
                            }
                        }
                    }

                    else
                    {
                        thisObjectsProperty.SetValue(thisObject, value, null);

                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    protected void Object_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (var item in e.NewItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                    }
                }
                break;

            case NotifyCollectionChangedAction.Remove:
                foreach (var item in e.OldItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged -= this.Object_PropertyChanged;
                    }
                }
                break;
        }

    }

    protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.NotifyPropertyChanged(e.PropertyName);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));

    }
}

SetValues 方法的第一个参数是将在视图模型中使用的 DependencyObject 类型。第二个参数是从 DomainService 的 Context.LoadOperation 返回的实体。

我的问题归结为当 INotifyCollectionChanged.CollectionChanged 触发时我需要能够使用集合的属性名称引发 PropertyChanged 事件。因此,如果有人有任何建议,我将不胜感激。提前致谢。

编辑
弄清楚如何获取触发事件的属性名称。这是我的 PropertyChangedEventHandler 的编辑版本。

protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var properties = this.GetType().GetProperties().Where(x => x.PropertyType == sender.GetType()).ToArray();

        foreach (var property in properties)
        {
            this.NotifyPropertyChanged(property.Name);
        }

        //this.NotifyPropertyChanged(e.PropertyName);
    }

基本上这就是我想要的,但显然我仍然没有做正确的事情。当添加另一种类型的属性 ObservableCollection 时,UIElement 仍未更新。

这是我的 DependencyObjects 和 ViewModel 的示例:

public class LOB : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(LOB), null);

    public ObservableCollection<Group> Groups
    {
        get { return (ObservableCollection<Group>)GetValue(GroupsProperty); }
        set
        {
            SetValue(GroupsProperty, value);
            NotifyPropertyChanged("Groups");
        }
    }

    public static readonly DependencyProperty GroupsProperty =
    DependencyProperty.Register("Groups", typeof(ObservableCollection<Group>), typeof(LOB), new PropertyMetadata(null, OnGroupsPropertyChanged));

    static void OnGroupsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += new NotifyCollectionChangedEventHandler(((LOB)obj).Object_CollectionChanged);
            ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(((LOB)obj).Object_PropertyChanged);
        }
        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= ((LOB)obj).Object_CollectionChanged;
            ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((LOB)obj).Object_PropertyChanged;
        }
    }

}

public class Group : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(Group), null);

    public String GroupName
    {
        get { return (String)GetValue(GroupNameProperty); }
        set
        {
            SetValue(GroupNameProperty, value);
            NotifyPropertyChanged("GroupName");
        }
    }

    public static readonly DependencyProperty GroupNameProperty =
    DependencyProperty.Register("GroupName", typeof(String), typeof(Group), null);

}

public class MyViewModel : DependencyObject
{
    public static readonly DependencyProperty LobCollectionProperty =
        DependencyProperty.Register("LobCollection",
            typeof(ObservableCollection<LOB>),
            typeof(MyViewModel),
            new PropertyMetadata(null, LobCollectionPropertyChanged));

    public ObservableCollection<LOB> LobCollection
    {
        get { return (ObservableCollection<MainBusinessLine>)GetValue(LobCollectionPropertyChanged); }
        set
        {
            SetValue(MainBusinessLineCollectionProperty, value);
            NotifyPropertyChanged("LobCollection");
        }
    }

    static void LobCollectionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var viewModel = obj as MyViewModel;

        if (viewModel == null)
            return;

        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= viewModel.LobCollection_Changed;
        }

        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += viewModel.LobCollection_Changed;
        }

    }

    void LobCollection_Changed(object sender, NotifyCollectionChangedEventArgs e)
    {
        NotifyPropertyChanged("LobCollection");
    }
}  

I have a base DependencyObject class where I have a method that takes an object, gets the properties, and for each property that is a type that implements INotifyPropertyChanged, I add a new PropertyChangedEventHandler. Now in the handler method, it gets the parameters of an object "sender" and the PropertyChangedEventArgs "e". My question is, does anyone know how to dynamically get the property name if sender is a property of a type that implements the INotifyPropertyChanged.

Here is what I'm working with:

public class BaseDependencyObject : DependencyObject, INotifyPropertyChanged
{
    public BaseDependencyObject()
    {

    }

    protected void SetValues(Object thisObject, Object entity)
    {
        try
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                var value = property.GetValue(entity, null);
                var valueIsEntity = value is System.ServiceModel.DomainServices.Client.Entity;
                var thisObjectsProperty = thisObject.GetType().GetProperty(property.Name);

                if (thisObjectsProperty != null && value != null)
                {
                    if (valueIsEntity)
                    {
                        if (thisObjectsProperty.PropertyType.GetInterface("INotifyPropertyChanged", true) != null)
                        {
                            var propertyInstance = Activator.CreateInstance(thisObjectsProperty.PropertyType);

                            ((INotifyPropertyChanged)propertyInstance).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                        }

                        SetValues(thisObjectsProperty, value);
                    }

                    else if (thisObjectsProperty.PropertyType.GetInterface("ICollection", true) != null
                        && thisObjectsProperty.PropertyType.GetGenericArguments().Count() > 0)
                    {
                        Type genericType = thisObjectsProperty.PropertyType.GetGenericArguments()[0];

                        var observableCollection = Activator.CreateInstance(thisObjectsProperty.PropertyType) as IList;

                        if (observableCollection is INotifyCollectionChanged)
                            ((INotifyCollectionChanged)observableCollection).CollectionChanged += this.Object_CollectionChanged;

                        if (observableCollection is INotifyPropertyChanged)
                            ((INotifyPropertyChanged)observableCollection).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);

                        foreach (var item in (IEnumerable)value)
                        {
                            var newItem = Activator.CreateInstance(genericType);

                            if (newItem != null)
                            {
                                SetValues(newItem, item);
                                observableCollection.Add(newItem);
                            }
                        }
                    }

                    else
                    {
                        thisObjectsProperty.SetValue(thisObject, value, null);

                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    protected void Object_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach (var item in e.NewItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
                    }
                }
                break;

            case NotifyCollectionChangedAction.Remove:
                foreach (var item in e.OldItems)
                {
                    if (item is INotifyPropertyChanged)
                    {
                        ((INotifyPropertyChanged)item).PropertyChanged -= this.Object_PropertyChanged;
                    }
                }
                break;
        }

    }

    protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.NotifyPropertyChanged(e.PropertyName);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));

    }
}

The SetValues method's first param is the DependencyObject type that will be used in the view model. The second param is the entity that is being returned from the DomainService's Context.LoadOperation.

What my issue boils down to is when the INotifyCollectionChanged.CollectionChanged fires I'm needing to be able to raise the PropertyChanged event with the collection's property name. So if anyone has any advise I would greatly appreciate it. Thanks in advance.

Edit
Figured out how to get the properties name that is firing the event. Here is an edited version of my PropertyChangedEventHandler.

protected void Object_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var properties = this.GetType().GetProperties().Where(x => x.PropertyType == sender.GetType()).ToArray();

        foreach (var property in properties)
        {
            this.NotifyPropertyChanged(property.Name);
        }

        //this.NotifyPropertyChanged(e.PropertyName);
    }

Basically this does what I was looking for, but aparentyly I am still not doing something right. The UIElement is still not updating when the ObservableCollection that is a property of another type is being added to.

Here is an example of my DependencyObjects and ViewModel:

public class LOB : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(LOB), null);

    public ObservableCollection<Group> Groups
    {
        get { return (ObservableCollection<Group>)GetValue(GroupsProperty); }
        set
        {
            SetValue(GroupsProperty, value);
            NotifyPropertyChanged("Groups");
        }
    }

    public static readonly DependencyProperty GroupsProperty =
    DependencyProperty.Register("Groups", typeof(ObservableCollection<Group>), typeof(LOB), new PropertyMetadata(null, OnGroupsPropertyChanged));

    static void OnGroupsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += new NotifyCollectionChangedEventHandler(((LOB)obj).Object_CollectionChanged);
            ((INotifyPropertyChanged)e.NewValue).PropertyChanged += new PropertyChangedEventHandler(((LOB)obj).Object_PropertyChanged);
        }
        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= ((LOB)obj).Object_CollectionChanged;
            ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((LOB)obj).Object_PropertyChanged;
        }
    }

}

public class Group : DependencyObject
{
    public Int32 ID
    {
        get { return (Int32)GetValue(IDProperty); }
        set
        {
            SetValue(IDProperty, value);
            NotifyPropertyChanged("ID");
        }
    }

    public static readonly DependencyProperty IDProperty =
    DependencyProperty.Register("ID", typeof(Int32), typeof(Group), null);

    public String GroupName
    {
        get { return (String)GetValue(GroupNameProperty); }
        set
        {
            SetValue(GroupNameProperty, value);
            NotifyPropertyChanged("GroupName");
        }
    }

    public static readonly DependencyProperty GroupNameProperty =
    DependencyProperty.Register("GroupName", typeof(String), typeof(Group), null);

}

public class MyViewModel : DependencyObject
{
    public static readonly DependencyProperty LobCollectionProperty =
        DependencyProperty.Register("LobCollection",
            typeof(ObservableCollection<LOB>),
            typeof(MyViewModel),
            new PropertyMetadata(null, LobCollectionPropertyChanged));

    public ObservableCollection<LOB> LobCollection
    {
        get { return (ObservableCollection<MainBusinessLine>)GetValue(LobCollectionPropertyChanged); }
        set
        {
            SetValue(MainBusinessLineCollectionProperty, value);
            NotifyPropertyChanged("LobCollection");
        }
    }

    static void LobCollectionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var viewModel = obj as MyViewModel;

        if (viewModel == null)
            return;

        if (e.OldValue != null)
        {
            ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= viewModel.LobCollection_Changed;
        }

        if (e.NewValue != null)
        {
            ((INotifyCollectionChanged)e.NewValue).CollectionChanged += viewModel.LobCollection_Changed;
        }

    }

    void LobCollection_Changed(object sender, NotifyCollectionChangedEventArgs e)
    {
        NotifyPropertyChanged("LobCollection");
    }
}  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

追星践月 2024-10-07 06:53:24

经过上面的对话,这是相当没有意义的,但我考虑了如何实现一个基类,当子类定义的属性中的集合发生更改时,该基类会触发 PropertyChanged 事件。正如我所说,这有点不标准,但我是这样做的。

class FancyCollectionAndPropertyChangedBase : INotifyPropertyChanged
{
    private Dictionary<ICollectionChanged, String> collectionNameLookup = new Dictionary<ICollectionChanged, String>();

    protected FancyCollectionAndPropertyChangedBase()
    {
        this.PropertyChanged += MyPropertyChanged;
    }

    private void MyPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(this.collectionNameLookup.ContainsValue(e.PropertyName)
        {
            KeyValuePair<INotifyCollectionChanged, String> oldValue = this.collectionNameLookup.First(kvp => kvp.Value == e.Name);
            oldValue.Key -= MyCollectionChanged;
            this.collecitonNameLookup.Remove(oldValue.Key);

            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
        else if(typeof(INotifyCollectionChanged).IsAssignableFrom(this.GetType().GetProperty(e.PropertyName,  BindingFlags.FlattenHierarchy).PropertyType))
        {
            // Note: I may have gotten the IsAssignableFrom statement, above, backwards. 
            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
    }

    private void MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.NotifyPropertyChanged(this.collectionNameLookup[sender];
    }
}

After our conversation above, this is rather moot, but I thought about how I'd implement a base class that fired PropertyChanged events when a collection changed in a property that was defined by the subclass. As I said, it's a bit non-standard, but here's how I'd do it.

class FancyCollectionAndPropertyChangedBase : INotifyPropertyChanged
{
    private Dictionary<ICollectionChanged, String> collectionNameLookup = new Dictionary<ICollectionChanged, String>();

    protected FancyCollectionAndPropertyChangedBase()
    {
        this.PropertyChanged += MyPropertyChanged;
    }

    private void MyPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(this.collectionNameLookup.ContainsValue(e.PropertyName)
        {
            KeyValuePair<INotifyCollectionChanged, String> oldValue = this.collectionNameLookup.First(kvp => kvp.Value == e.Name);
            oldValue.Key -= MyCollectionChanged;
            this.collecitonNameLookup.Remove(oldValue.Key);

            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
        else if(typeof(INotifyCollectionChanged).IsAssignableFrom(this.GetType().GetProperty(e.PropertyName,  BindingFlags.FlattenHierarchy).PropertyType))
        {
            // Note: I may have gotten the IsAssignableFrom statement, above, backwards. 
            INotifyCollectionChanged collection = this.GetType().GetProperty(e.PropertyName, BindingFlags.FlattenHierarchy).GetValue(this, null);
            collection.CollectionChanged += MyCollectionChanged;
            this.collectionNameLookup.Add(collection, e.Name);
        }
    }

    private void MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        this.NotifyPropertyChanged(this.collectionNameLookup[sender];
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文