最佳化效能:資料繫結
Windows Presentation Foundation (WPF) 資料繫結提供簡單且一致的方式,讓應用程式能夠呈現資料並與其互動。 元素可以與各種數據源的資料進行繫結,格式為 CLR 物件和 XML。
本主題提供資料繫結的效能建議。
資料繫結參考的解析方式
在討論資料繫結效能問題之前,請務必探索 Windows Presentation Foundation (WPF) 數據系結引擎如何解析繫結的物件參考。
Windows Presentation Foundation (WPF) 數據系結的來源可以是任何 CLR 物件。 您可以繫結至 CLR 物件的屬性、子屬性或索引器。 繫結參考是使用 Microsoft .NET Framework 解析或以 ICustomTypeDescriptor 解析。 以下是三種解析繫結用之物件參考的方法。
第一個方法涉及使用反映。 在此情況下,會使用 PropertyInfo 物件來探索屬性的特性,並提供屬性中繼資料的存取權。 使用 ICustomTypeDescriptor 介面時,資料繫結引擎會使用此介面來存取屬性值。 ICustomTypeDescriptor 介面在物件沒有靜態屬性集的情況下特別有用。
您可以實作 INotifyPropertyChanged 介面或使用與 TypeDescriptor 相關聯的變更通知,來提供屬性變更通知。 不過,實作屬性變更通知的建議策略是使用 INotifyPropertyChanged。
如果來源物件是 CLR 物件,而且來源屬性是 CLR 屬性,則 Windows Presentation Foundation (WPF) 數據系結引擎必須先使用來源物件的反映來取得 TypeDescriptor,然後查詢 PropertyDescriptor。 這個反映作業序列從效能觀點來看可能非常耗時。
解析對象參考的第二個方法涉及一個實作 INotifyPropertyChanged 介面的 CLR 來源物件,以及一個 CLR 屬性。 在此情況下,資料繫結引擎會直接對來源類型使用反映,並取得必要的屬性。 這仍不是最佳的方法,但它的工作集需求的成本會比第一種方法低。
第三個解析物件參考的方法涉及 DependencyObject 的來源物件,以及一個是 DependencyProperty 的來源屬性。 在此情況下,資料繫結引擎不必使用反映。 相反地,屬性引擎和資料繫結引擎會一起獨立解析屬性參考。 這是解析用於資料繫結之物件參考的最佳方法。
下表會使用這三種方法,比較資料繫結 Text 屬性 TextBlock 元素的速度。
繫結 TextBlock 的 Text 屬性 | 繫結時間 (毫秒) | 轉譯時間 -- 包括繫結 (毫秒) |
---|---|---|
CLR 物件的屬性 | 115 | 314 |
實作 INotifyPropertyChanged 的 CLR 對象的屬性 | 115 | 305 |
對 DependencyObject 的 DependencyProperty。 | 90 | 263 |
系結至大型 CLR 物件
當您數據系結至具有數千個屬性的單一 CLR 物件時,效能會有很大的影響。 您可以將單一物件分割成多個具有較少屬性的多個 CLR 物件,藉此將影響降到最低。 數據表會顯示數據系結至單一大型 CLR 物件與多個較小對象的系結和轉譯時間。
資料繫結 1000 個 TextBlock 物件 | 繫結時間 (毫秒) | 轉譯時間 -- 包括繫結 (毫秒) |
---|---|---|
對具有1000個屬性的 CLR 物件 | 950 | 1200 |
至 1000 個具有一個屬性的 CLR 物件 | 115 | 314 |
繫結至 ItemsSource
假設您有一個 CLRList<T> 物件,其中包含您想要在 ListBox中顯示的員工清單。 若要建立這兩個物件之間的對應,您可以將員工清單繫結至 ListBox 的 ItemsSource 屬性。 不過,假設您有新的員工加入您的群組。 您可能會認為,若要將這個新人插入已繫結的 ListBox 值,您只要將這個人加入員工清單,這項變更便預期會被資料繫結引擎自動辨識。 這個假設證明是錯的。實際上,變更不會自動反映在 ListBox。 這是因為 CLRList<T> 物件不會自動引發集合變更事件。 若要取得 ListBox 以挑選變更,您必須重新建立員工清單,並將其重新附加至 ListBox 的 ItemsSource 屬性。 雖然這個解決方案有效,但它造成了嚴重的效能影響。 每次您將 ListBox 的 ItemsSource 重新指派給新物件時, ListBox 會先拋棄其先前的項目,並重新產生其整個清單。 如果您的 ListBox 對應到複雜 DataTemplate,對效能影響就會放大。
對此問題有一個非常有效率的解決方案,就是讓您的員工清單成為 ObservableCollection<T>。 ObservableCollection<T> 物件會觸發資料繫結引擎可接收的變更通知。 事件會新增或移除 ItemsControl 的項目,而不需要重新產生整個清單。
下表顯示新增一個項目時,更新 ListBox (關閉 UI 虛擬化) 所花的時間。 第一行中的數字代表 CLRList<T> 對象綁定至 ListBox 元素的 ItemsSource時經過的時間。 第二列中的數值代表 ObservableCollection<T> 物件繫結至 ListBox 元素的 ItemsSource 時所經過的時間。 請注意到使用 ObservableCollection<T> 資料繫結策略的顯著節省時間效果。
資料繫結 ItemsSource | 1 個項目的更新時間 (毫秒) |
---|---|
對 CLRList<T> 物件 | 16:56 |
對 ObservableCollection<T> | 20 |
將 IList 繫結至 ItemsControl 而非 IEnumerable
如果您選擇將 IList<T> 或 IEnumerable 繫結至 ItemsControl 物件,請選擇 IList<T> 物件。 繫結 IEnumerable 至 ItemsControl 會強制 WPF 建立包裝函式 IList<T> 物件,這表示您的效能會受到第二個物件不必要的額外負荷影響。
請勿將 CLR 物件轉換成 XML Just for Data Binding。
WPF 可讓您將數據系結至 XML 內容;不過,數據系結至 XML 內容的速度比數據系結 CLR 物件慢。 如果唯一的目的是數據系結,請勿將 CLR 對象數據轉換成 XML。