簡體   English   中英

使用INotifyPropertyChanged更新ObservableCollection項屬性

[英]Updating ObservableCollection Item properties using INotifyPropertyChanged

檢查以確保我的假設是正確的。

我有一個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;
}

在上面的案例中,緯度和經度都會觸發他們的事件。

既然我的班級有很多屬性,那么還有一個更好的方法嗎?

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

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

item.RaisePropertyChanged("");

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

為此,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 在某些情況下可能仍然行為不端。
你還可以添加一個布爾deep的方法和控制是否應該深負載如果可能需要的。 (只需添加|| !deep到那個長if-expression)

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

Edit2:因為PropertyInfo.GetValue返回一個object我以前的代碼沒有遞歸加載,不幸的是,你必須顯式傳遞一個Type,請參閱舊版本的修訂版。

編輯3:如果沒有類型參考使這項工作的方法看到我問的這個專門的問題 但是,這並未解決其他問題,如循環引用和枚舉對象的屬性。

我認為你可以重載=運算符並在那里進行屬性賦值。 然后將生成PropertyChanged事件,您仍將使用與第一個示例中相同的語法。

Device類必須實現接口INotifyPropertyChanged。然后為每個屬性觸發notify屬性更改事件asuall。

這將自動啟用屬性更改通知。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM