检查以确保我的假设是正确的。
我有一个ObservableCollection类。我正在调用Web服务并检索一组设备。然后我枚举ObservableCollection并将每个项目设置为从Web服务检索到的相应设备。我所厌烦的设备具有与ObservableCollection中的项不同的属性值,但PropertyChanged事件未触发。
我假设这是ByDesign,为了让PropertyChanged事件触发,我实际上必须枚举每个属性并设置值?
例如,在下面的情况中,任何Device类属性都不会触发PropertyChanged事件。
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;
}
但是,如果我手动更新每个属性,我就是在做生意:
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;
}
在上面的案例中,纬度和经度都会触发他们的事件。
由于我的课有很多属性,有没有比一个一个更好的方法呢?
答案 0 :(得分:3)
在第一个示例中,设置集合中的项目将触发CollectionChanged事件,而不是单个项目的PropertyChanged事件。
您可以通过为PropertyChanged事件指定空字符串来通知所有属性。例如:
item.RaisePropertyChanged("");
其中 RaisePropertyChanged 是一个公共方法,用于调用INotifyPropertyChanged实现的PropertyChanged事件。
答案 1 :(得分:1)
为此,Load方法可能很有用,因此您不会覆盖引用,而是设置旧对象的所有属性。这是我刚刚编写的一个通用扩展方法,它将分配所有可写属性,这非常粗糙:
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
分配所有值(如果它们是属性)。
编辑:使该方法递归,因此它将调用Load
以获取非基本类型或值类型(或字符串)的属性。在某些情况下可能仍然行为不端
您还可以向方法添加一个bool deep
,并控制它是否应该深度加载(如果可能需要)。 (只需将|| !deep
添加到那个长if-expression)
注意:如果您愿意,您当然也可以覆盖对象引用并使用反射来为所有不同的属性引发PropertyChanged事件。无论哪种方式,您都不需要手动处理每个属性。
Edit2:因为PropertyInfo.GetValue
返回object
我以前的代码没有递归加载,不幸的是,你必须显式传递一个Type,请参阅旧版本的修订版。
编辑3:有关在没有“类型”引用的情况下使其工作的方法,请参阅我提出的dedicated question。但是,这并未解决其他问题,如循环引用和枚举对象的属性。
答案 2 :(得分:0)
我认为你可以重载=
运算符并在那里进行属性赋值。然后将生成PropertyChanged事件,您仍将使用与第一个示例中相同的语法。
答案 3 :(得分:0)
Device类必须实现接口INotifyPropertyChanged。然后,对于每个属性,将notify属性更改为eventuall事件。
这将自动启用属性更改通知。