Optimieren der Leistung: Datenbindung

Die Datenbindung in Windows Presentation Foundation (WPF) bietet für Anwendungen eine einfache und konsistente Möglichkeit, Daten darzustellen und mit ihnen zu interagieren. Elemente können in Form von CLR-Objekten und XML an Daten aus einer Vielzahl von Datenquellen gebunden werden.

In diesem Thema erhalten Sie Empfehlungen bezüglich der Datenbindung.

So werden Datenbindungsverweise aufgelöst

Vor der Erläuterung von Problemen bei der Leistung der Datenbindung kann es sinnvoll sein, zu erfahren, wie die Windows Presentation Foundation (WPF)-Datenbindungs-Engine Objektverweise für die Bindung auflöst.

Die Quelle einer Windows Presentation Foundation (WPF)-Datenbindung kann ein beliebiges CLR-Objekt sein. Sie können an Eigenschaften, Untereigenschaften oder Indexer eines CLR-Objekts binden. Die Bindungsverweise werden mithilfe einer Microsoft .NET Framework-Reflexion oder ICustomTypeDescriptor aufgelöst. Dies sind drei Methoden zu Auflösung von Objektverweisen für die Bindung.

In der ersten Methode verwenden Sie die Reflektion. In diesem Fall wird das PropertyInfo-Objekt verwendet, um die Attribute der Eigenschaft zu erfahren und Zugriff auf die Metadaten der Eigenschaft zu erhalten. Wenn Sie die ICustomTypeDescriptor-Schnittstelle verwenden, verwendet die Datenbindungs-Engine diese Schnittstelle, um auf die Eigenschaftswerte zuzugreifen. Die ICustomTypeDescriptor-Schnittstelle ist besonders dann nützlich, wenn das Objekt keinen statischen Satz von Eigenschaften aufweist.

Änderungsbenachrichtigungen für Eigenschaften können entweder durch Implementieren der INotifyPropertyChanged-Schnittstelle oder durch Verwenden der Änderungsbenachrichtigungen in Verbindung mit TypeDescriptor bereitgestellt werden. Allerdings wird empfohlen, Benachrichtigungen für Eigenschaftenänderungen mit INotifyPropertyChanged zu implementieren.

Wenn das Quellobjekt ein CLR-Objekt ist, und die Quelleigenschaft eine CLR-Eigenschaft ist, muss die Windows Presentation Foundation (WPF)-Datenbindungs-Engine zunächst die Reflektion auf das Quellobjekt anwenden, um ein TypeDescriptor-Element zu erhalten, und anschließend ein PropertyDescriptor-Element abfragen. Diese Folge von Reflektionsvorgängen kann hinsichtlich der Leistung sehr zeitaufwändig sein.

In der zweiten Methode für das Auflösen von Objektverweisen implementiert ein CLR-Quellobjekt die INotifyPropertyChanged-Schnittstelle; dabei ist die Quelleigenschaft eine CLR-Eigenschaft. In diesem Fall wendet die Datenbindungs-Engine die Reflektion direkt auf die Quelle an und erhält die erforderliche Eigenschaft. Dies stellt immer noch nicht die optimale Methode dar, aber sie hat weniger Workingsetanforderungen als die erste Methode.

In der dritten Methode für das Auflösen von Objektverweisen implementiert ein Quellobjekt ein DependencyObject und eine Quelleigenschaft, die eine DependencyProperty ist. In diesem Fall muss die Datenbindungs-Engine keine Reflektion verwenden. Stattdessen lösen die Eigenschaften-Engine und die Datenbindungs-Engine gemeinsam und unabhängig den Eigenschaftenverweis auf. Dies stellt die optimale Methode für das Auflösen von Objektverweisen für die Datenbindung dar.

Die Tabelle unten vergleicht die Geschwindigkeit der Datenbindung der Text-Eigenschaft von tausend TextBlock-Elementen anhand von drei Methoden.

Bindung einer Text-Eigenschaft an einen TextBlock Bindungszeit (in ms) Renderingzeit, einschließlich Bindung (in ms)
An die Eigenschaft eines CLR-Objekts 115 314
An eine Eigenschaft eines CLR-Objekts, das INotifyPropertyChanged implementiert 115 305
An eine DependencyProperty eines DependencyObject. 90 263

Bindung an große CLR-Objekte

Wenn Sie Daten an ein einzelnes CLR-Objekt mit tausend Eigenschaften binden, beeinträchtigt dies die Leistung deutlich. Sie können die Beeinträchtigung verringern, indem Sie das einzelne Objekt in mehrere CLR-Objekte aufteilen, die weniger Eigenschaften haben. In der unten stehenden Tabelle werden die Bindungs- und Renderingzeiten für die Datenbindung an ein einzelnes großes CLR-Objekt und an mehrere kleinere Objekte dargestellt.

Datenbindung an 1000 TextBlock-Objekte Bindungszeit (in ms) Renderingzeit, einschließlich Bindung (in ms)
An ein CLR-Objekt mit 1.000 Eigenschaften 950 1200
An 1.000 CLR-Objekte mit einer Eigenschaft 115 314

Bindung an eine ItemsSource

Stellen Sie sich ein Szenario mit einem CLR-List<T>-Objekt vor, das eine Liste von Mitarbeitern enthält, die Sie in einer ListBox anzeigen möchten. Um eine Verbindung zwischen diesen beiden Objekten herzustellen, müssen Sie Ihre Mitarbeiterliste an die ItemsSource-Eigenschaft des ListBox-Elements binden. Gehen Sie nun davon aus, dass ein neuer Angestellter dazu kommt. Jetzt könnten Sie denken, dass Sie diese Person einfach Ihrer Mitarbeiterliste hinzufügen müssen, um sie in die gebundenen ListBox-Werte einzubeziehen, und davon ausgehen, dass diese Änderung automatisch von der Datenbindungs-Engine erkannt wird. Dem ist nicht so; tatsächlich wird die Änderung nicht automatisch in das ListBox-Element übernommen. Dies liegt daran, dass das CLR-List<T>-Objekt nicht automatisch ein CollectionChanged-Ereignis auslöst. Sie müssten Ihre Mitarbeiterliste neu erstellen und wieder an die ItemsSource-Eigenschaft des ListBox-Elements anfügen, um die Änderungen im ListBox-Element zu übernehmen. Obwohl diese Lösung funktioniert, beeinträchtigt sie die Leistung deutlich. Jedes Mal, wenn Sie ItemsSource von ListBox einem neuen Objekt zuweisen, wirft das ListBox-Element zuerst seine vorherigen Elemente weg und generiert seine komplette Liste noch einmal neu. Die Leistungsbeeinträchtigung wird noch verstärkt, wenn Ihr ListBox-Element einem komplexen DataTemplate-Element zugeordnet ist.

Dieses Problem können Sie äußerst effizient lösen, indem Sie Ihre Mitarbeiterliste zu einer ObservableCollection<T>-Klasse machen. Ein ObservableCollection<T>-Objekt löst eine Änderungsbenachrichtigung aus, die die Datenbindungs-Engine enthalten kann. Das Ereignis entfernt ein Element aus einem ItemsControl oder fügt es hinzu, ohne die gesamte Liste erneut generieren zu müssen.

In der unten stehenden Tabelle wird die Zeit dargestellt, die für das Aktualisieren des ListBox-Elements beansprucht wird, wenn ein Element hinzugefügt wird (wenn die Virtualisierung der Benutzeroberfläche deaktiviert ist). Die Zahl in der ersten Reihe steht für die verstrichene Zeit, wenn das CLR-List<T>-Objekt an das ItemsSource-Element eines ListBox-Elements gebunden ist. Die Zahl in der zweiten Reihe steht für die verstrichene Zeit, wenn ein ObservableCollection<T>-Element an das ItemsSource-Element des ListBox-Elements gebunden ist. Sie können erkennen, dass durch die Datenbindungsstrategie ObservableCollection<T> deutlich Zeit eingespart wird.

Datenbindung der ItemsSource Zeit für das Aktualisieren eines Elements (in ms)
An ein CLR-List<T>-Objekt 1656
An ein ObservableCollection<T> 20

Bindung von IList an ItemsControl und nicht an IEnumerable

Wenn Sie eine Wahl zwischen der Bindung eines IList<T>- oder IEnumerable-Objekts an ein ItemsControl-Objekt haben, wählen Sie das IList<T>-Objekt aus. Durch das Binden eines IEnumerable-Objekts an ein ItemsControl-Objekt wird WPF dazu gezwungen, ein IList<T>-Wrapperobjekt zu erstellen, wodurch Ihre Leistung durch den unnötigen Mehraufwand eines zweiten Objekts beeinträchtigt wird.

Konvertieren Sie CLR-Objekte nicht nur für die Datenbindung in XML

Mit WPF können Sie eine Datenbindung an XML-Inhalt durchführen; allerdings ist die Datenbindung an XML-Inhalt langsamer als an CLR-Objekte. Konvertieren Sie CLR-Objektdaten nicht nur für die Datenbindung in XML.

Weitere Informationen