2011-02-08 121 views
4

檢查以確保我的假設是正確的。使用INotifyPropertyChanged更新ObservableCollection項目屬性

我有一個ObservableCollection類。我正在調用Web服務並檢索一組設備。然後我列舉ObservableCollection並將每個項目設置爲從Web服務檢索的相應設備。我懷疑的設備具有與ObservableCollection中的項目不同的屬性值,但PropertyChanged事件不會觸發。

我認爲這是ByDesign,並且爲了讓PropertyChanged事件觸發,我實際上必須枚舉每個屬性並設置值?

例如,在下面的情況下,沒有任何PropertyChanged事件在任何Device類屬性上觸發。

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

在上述情況下,經度和緯度火他們的活動。

由於我的課有一堆屬性有沒有更好的方法來做到這一點比一個一個?

回答

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添加到那個long if表達式中)

注意:如果您願意,您當然也可以覆蓋您的對象引用並使用反射爲所有不同的屬性引發PropertyChanged事件。無論哪種方式,你不需要手動處理每個屬性。

EDIT2:因爲PropertyInfo.GetValue返回一個object我以前的代碼沒有遞歸加載,遺憾的是這樣,你必須明確地傳遞一個類型,見老版本的修訂。

編輯3:有關如何使這項工作沒有類型參考見這dedicated question我問。然而,這並沒有解決其他問題,如循環引用和枚舉對象的屬性。

+0

嘿,這工作得很好。我在Device中的一種類型是屬性類,它是類。所以我不得不調用item.Load(currentDevice)和item.Location.Load(currentDevice.Location) – 2011-02-08 17:14:22

0

我認爲你可以重載=運營商,並在那裏做屬性分配。那麼將生成PropertyChanged事件,並且您將仍然具有與第一個示例中相同的語法。

+1

這真的很酷,但魔術師可能會嚇人。 – bryanbcook 2011-02-08 14:28:12

+0

@bryanbcook哈哈可以有點..:D ..但我建議OP作爲OP想要在提到的語法中使用它。這隻能通過這個過載 – 2011-02-08 14:36:38

3

在第一個示例中,設置集合中的項目將觸發CollectionChanged事件,而不是單個項目的PropertyChanged事件。

您可以通過爲PropertyChanged事件指定一個空字符串來通知所有屬性。例如:

item.RaisePropertyChanged(""); 

其中RaisePropertyChanged是調用INotifyPropertyChanged的實施PropertyChanged事件的公共方法。

+0

我會使用`String.Empty`,它有點乾淨。 – 2011-02-08 16:26:10

0

設備類必須實現接口INotifyPropertyChanged。然後爲每個屬性觸發通知屬性更改事件作​​爲usuall。

這將使屬性自動更改通知。

相關問題