最佳化效能:資料繫結

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
實作之 CLR 物件的 屬性 INotifyPropertyChanged 115 305
DependencyProperty至 的 DependencyObject 90 263

繫結至大型 CLR 物件

當您資料系結至具有數千個屬性的單一 CLR 物件時,效能會有很大的影響。 您可以將單一物件分割成多個具有較少屬性的 CLR 物件,以最小化此影響。 資料表會顯示資料系結至單一大型 CLR 物件與多個較小物件的系結和轉譯時間。

資料繫結 1000 個 TextBlock 物件 繫結時間 (毫秒) 轉譯時間 -- 包括繫結 (毫秒)
使用 1000 個屬性的 CLR 物件 950 1200
使用一個屬性將 CLR 物件設為 1000 個 115 314

繫結至 ItemsSource

假設您有 CLR List<T> 物件,其中包含您想要在 中 ListBox 顯示的員工清單。 若要建立這兩個物件之間的對應,您可以將員工清單系結至 ItemsSourceListBox 屬性。 不過,假設您有新的員工加入您的群組。 您可能會認為,若要將此新人員插入系結 ListBox 值,您只需將這個人新增至員工清單,並預期資料系結引擎會自動辨識這項變更。 這種假設會證明是錯誤的:實際上,變更不會自動反映在 中 ListBox 。 這是因為 CLR List<T> 物件不會自動引發集合變更事件。 若要取得 ListBox 以挑選變更,您必須重新建立員工清單,並將它重新附加至 ItemsSourceListBox 屬性。 雖然這個解決方案有效,但它造成了嚴重的效能影響。 每次您將 重新指派 ItemsSourceListBox 給新的 物件時,第 ListBox 一個會擲回其先前的專案,並重新產生其整個清單。 如果您的 ListBox 對應至複雜 DataTemplate ,效能影響就會放大。

此問題的一個非常有效率的解決方案是讓您的員工清單成為 ObservableCollection<T> 。 物件 ObservableCollection<T> 會引發資料系結引擎可接收的變更通知。 事件會從 ItemsControl 新增或移除專案,而不需要重新產生整個清單。

下表顯示新增某個專案時更新 ListBox 的時間(UI 虛擬化已關閉)。 第一個資料列中的數位代表 CLR List<T> 物件系結至 ListBox 元素 ItemsSource 的經過時間。 第二個數據列中的數位代表系結至 ListBox 元素 ItemsSource 的經過時間 ObservableCollection<T> 。 請注意使用 ObservableCollection<T> 資料系結策略節省大量時間。

資料繫結 ItemsSource 1 個項目的更新時間 (毫秒)
對 CLR List<T> 物件 1656
ObservableCollection<T> 20

將 IList 繫結至 ItemsControl 而非 IEnumerable

如果您在將 或 IEnumerable 系結 IList<T>ItemsControl 物件之間有選擇,請選擇 IList<T> 物件。 系結 IEnumerableItemsControl 會強制 WPF 建立包裝函 IList<T> 式物件,這表示您的效能會受到第二個物件不必要的額外負荷所影響。

不要只為了資料繫結而將 CLR 物件轉換成 XML。

WPF 可讓您將資料系結至 XML 內容;不過,資料系結至 XML 內容的速度比資料系結至 CLR 物件的速度慢。 如果唯一的用途是資料系結,請勿將 CLR 物件資料轉換成 XML。

另請參閱