使用INotifyPropertyChanged更新ObservableCollection Item属性 [英] Updating ObservableCollection Item properties using INotifyPropertyChanged

查看:68
本文介绍了使用INotifyPropertyChanged更新ObservableCollection Item属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

检查以确保我的假设正确.

Checking to make sure my assumptions are correct.

我有一个ObservableCollection类.我正在调用Web服务并检索一系列设备.然后,我枚举ObservableCollection并将每个项目设置为从Web服务检索到的相应设备.我获取的设备的属性值与ObservableCollection中的项目不同,但是PropertyChanged事件没有触发.

I have an ObservableCollection class. I am calling a web service and retrieving an array of Devices. I am then enumerating the ObservableCollection and setting each item to the corresponding device retrieved from the web service. The devices I rerieved have different property values than the items in the ObservableCollection, but PropertyChanged events are not firing.

我假定这是ByDesign,为了触发PropertyChanged事件,我实际上必须枚举每个属性并设置值?

I assume that this is ByDesign and that in order to have the PropertyChanged event fire I actually have to enumerate each property and set the value?

例如,在以下情况下,任何Device类属性都不会触发PropertyChanged事件.

For example, in the case below, no PropertyChanged events fire on any of the Device class properties.

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'm in 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 case above, both Latitude and Longitude fire their events.

由于我的课有很多属性,有没有比逐个方法更好的方法了?

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

推荐答案

为此,Load方法可能很有用,因此您不必覆盖引用,而是设置旧对象的所有属性.这是我刚写的通用扩展方法,它将分配所有可写属性,这很粗糙:

For that a Load method might be useful, so you don't overwrite the reference but set all the properties of the old object instead. Here's a generic extension method i just wrote which will assign all the writeable properties, it's very rough:

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

您应该可以拨打电话

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

分配所有值(如果它们是属性).

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

使该方法具有递归性,以便为不是原始类型或值类型(或字符串)的属性调用 Load .在某些情况下,仍然可能行为不当.
您还可以在方法中添加布尔值 deep 并控制是否需要深度加载.(只需将 ||!deep 添加到该长的if-expression中)

Made the method recursive so it will call Load for properties which are not of a primitive type or value type (or string). Probably still misbehaves in some cases.
You could also add a bool deep to the method and control if it should deep-load if that might be needed. (Just add || !deep to that long if-expression)

注意:当然,您也可以覆盖对象引用,并根据需要使用反射来引发所有不同属性的PropertyChanged事件.无论哪种方式,您都不需要手动处理每个属性.

Note: You could of course also overwrite your object reference and use reflection to raise the PropertyChanged event for all the different properties if you prefer. Either way you don't need to handle each property manually.

Edit2 :由于 PropertyInfo.GetValue 返回了 object ,我之前的代码没有递归加载,因此,您必须显式地传递一个输入,请查看旧版本的修订版本.

Because PropertyInfo.GetValue returns an object my previous code did not load recursively, unfortunately with this you have to explicitly pass a Type, see revisions for old version.

Edit3 :有关在没有类型"引用的情况下进行此工作的方法,请参见以下

For ways to make this work without the Type reference see this dedicated question that i asked. This however does not address other issues like circular references and properties that enumerate objects.

这篇关于使用INotifyPropertyChanged更新ObservableCollection Item属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆