Optymalizacja wydajności: powiązanie danych

Powiązania danych platformy Windows Presentation Foundation (WPF) zapewniają prosty i spójny sposób prezentowania danych i interakcji z nimi w aplikacjach. Elementy mogą być powiązane z danymi z różnych źródeł danych w postaci obiektów CLR i XML.

Ten temat zawiera zalecenia dotyczące wydajności powiązania danych.

Jak są rozwiązywane odwołania do powiązań danych

Przed omówieniem problemów z wydajnością powiązania danych warto zapoznać się z tym, jak aparat powiązania danych programu Windows Presentation Foundation (WPF) rozwiązuje odwołania do obiektów w celu powiązania.

Źródłem powiązania danych programu Windows Presentation Foundation (WPF) może być dowolny obiekt CLR. Można powiązać z właściwościami, podwłaściami lub indeksatorami obiektu CLR. Odwołania do powiązań są rozwiązywane przy użyciu odbicia programu Microsoft .NET Framework lub ICustomTypeDescriptor. Poniżej przedstawiono trzy metody rozpoznawania odwołań do obiektów dla powiązania.

Pierwsza metoda obejmuje użycie odbicia. W takim przypadku PropertyInfo obiekt jest używany do odnajdywania atrybutów właściwości i zapewnia dostęp do metadanych właściwości. W przypadku korzystania z interfejsu ICustomTypeDescriptor aparat powiązania danych używa tego interfejsu do uzyskiwania dostępu do wartości właściwości. Interfejs ICustomTypeDescriptor jest szczególnie przydatny w przypadkach, gdy obiekt nie ma statycznego zestawu właściwości.

Powiadomienia o zmianie właściwości mogą być udostępniane przez zaimplementowanie interfejsu INotifyPropertyChanged lub przy użyciu powiadomień o zmianie skojarzonych z elementem TypeDescriptor. Jednak preferowaną strategią implementacji powiadomień o zmianie właściwości jest użycie polecenia INotifyPropertyChanged.

Jeśli obiekt źródłowy jest obiektem CLR, a właściwość źródłowa jest właściwością CLR, aparat powiązania danych programu Windows Presentation Foundation (WPF) musi najpierw użyć odbicia względem obiektu źródłowego, aby pobrać TypeDescriptorelement , a następnie wykonać zapytanie dotyczące elementu PropertyDescriptor. Ta sekwencja operacji odbicia jest potencjalnie bardzo czasochłonna z perspektywy wydajności.

Druga metoda rozpoznawania odwołań do obiektów obejmuje obiekt źródłowy CLR, który implementuje INotifyPropertyChanged interfejs, oraz właściwość źródłową, która jest właściwością CLR. W tym przypadku aparat powiązania danych używa odbicia bezpośrednio na typ źródłowy i pobiera wymaganą właściwość. Nadal nie jest to optymalna metoda, ale będzie kosztować mniej wymagań zestawu roboczego niż pierwsza metoda.

Trzecia metoda rozpoznawania odwołań do obiektów obejmuje obiekt źródłowy, który jest właściwością DependencyObject źródłową i , która jest właściwością DependencyProperty. W takim przypadku aparat powiązania danych nie musi używać odbicia. Zamiast tego aparat właściwości i aparat powiązania danych wspólnie rozpoznają odwołanie do właściwości niezależnie. Jest to optymalna metoda rozpoznawania odwołań do obiektów używanych do powiązania danych.

Poniższa tabela porównuje szybkość powiązania Text danych z właściwością jednego tysiąca TextBlock elementów przy użyciu tych trzech metod.

Wiązanie właściwości Text obiektu TextBlock Czas powiązania (ms) Czas renderowania — obejmuje powiązanie (ms)
Do właściwości obiektu CLR 210 314
Do właściwości obiektu CLR, który implementuje INotifyPropertyChanged 210 305
Do obiektu DependencyPropertyDependencyObject. 90 263

Wiązanie z dużymi obiektami CLR

Istnieje znaczący wpływ na wydajność, gdy dane są powiązane z pojedynczym obiektem CLR z tysiącami właściwości. Ten wpływ można zminimalizować, dzieląc pojedynczy obiekt na wiele obiektów CLR z mniejszą liczbą właściwości. W tabeli przedstawiono czasy wiązania i renderowania dla powiązania danych z pojedynczym dużym obiektem CLR w porównaniu z wieloma mniejszymi obiektami.

Powiązanie danych 1000 obiektów TextBlock Czas powiązania (ms) Czas renderowania — obejmuje powiązanie (ms)
Do obiektu CLR z 1000 właściwościami 950 1200
Do 1000 obiektów CLR z jedną właściwością 210 314

Wiązanie z elementem ItemsSource

Rozważmy scenariusz, w którym znajduje się obiekt CLR List<T> zawierający listę pracowników, które mają być wyświetlane w obiekcie ListBox. Aby utworzyć korespondencję między tymi dwoma obiektami, należy powiązać listę pracowników z właściwością ItemsSourceListBox. Załóżmy jednak, że masz nowego pracownika dołączanego do grupy. Możesz pomyśleć, że aby wstawić tę nową osobę do powiązanych ListBox wartości, wystarczy dodać tę osobę do listy pracowników i oczekiwać, że ta zmiana zostanie automatycznie rozpoznana przez aparat powiązania danych. To założenie okaże się fałszywe; w rzeczywistości zmiana nie zostanie odzwierciedlona automatycznie ListBox . Dzieje się tak, ponieważ obiekt CLR List<T> nie zgłasza automatycznie zdarzenia zmiany kolekcji. Aby pobrać ListBox zmiany, należy ponownie utworzyć listę pracowników i ponownie dołączyć ją do ItemsSource właściwości obiektu ListBox. Chociaż to rozwiązanie działa, wprowadza ogromny wpływ na wydajność. Za każdym razem, gdy ponownie przypiszesz element ItemsSourceListBox do nowego obiektu, ListBox pierwszy wyrzuca jego poprzednie elementy i ponownie generuje całą listę. Wpływ na wydajność jest powiększony, jeśli ListBox mapuje się na złożony DataTemplateelement .

Bardzo wydajnym rozwiązaniem tego problemu jest uczynienie listy pracowników listą ObservableCollection<T>. Obiekt ObservableCollection<T> zgłasza powiadomienie o zmianie, które aparat powiązania danych może odbierać. Zdarzenie dodaje lub usuwa element z elementu ItemsControl bez konieczności ponownego generowania całej listy.

W poniższej tabeli przedstawiono czas aktualizacji ListBox (z wyłączoną wirtualizacją interfejsu użytkownika) po dodaniu jednego elementu. Liczba w pierwszym wierszu reprezentuje czas, który upłynął, gdy obiekt CLR List<T> jest powiązany z ListBox elementem ItemsSource. Liczba w drugim wierszu reprezentuje czas, który upłynął, gdy element ObservableCollection<T> jest powiązany z ListBox elementem ItemsSource. Zwróć uwagę na znaczne oszczędności czasu przy użyciu ObservableCollection<T> strategii wiązania danych.

Powiązanie danych z elementem ItemsSource Czas aktualizacji dla 1 elementu (ms)
Do obiektu CLR List<T> 1656
Do ObservableCollection<T> 20

Wiązanie listy IList z elementamiKontrolowanie nie jest możliwe do wyliczenia

Jeśli masz wybór między powiązaniem obiektu IList<T> lub z obiektem IEnumerableItemsControl , wybierz IList<T> obiekt. Powiązanie IEnumerable z siłą ItemsControl WPF w celu utworzenia obiektu otoki IList<T> , co oznacza, że wydajność ma wpływ na niepotrzebne obciążenie drugiego obiektu.

Nie konwertuj obiektów CLR na XML tylko dla powiązania danych.

WPF umożliwia powiązanie danych z zawartością XML; jednak powiązanie danych z zawartością XML jest wolniejsze niż powiązanie danych z obiektami CLR. Nie konwertuj danych obiektu CLR na XML, jeśli jedynym celem jest powiązanie danych.

Zobacz też