Freigeben über


Übersicht über Datenbindung

Die Datenbindung in Windows Presentation Foundation (WPF) bietet eine einfache und konsistente Möglichkeit für Apps zum Präsentieren und Interagieren mit Daten. Elemente können in Form von .NET-Objekten und XML an Daten verschiedener Arten von Datenquellen gebunden werden. AlleContentControl, wie z. B. Button und ItemsControl, verfügen über integrierte Funktionen, um eine flexible Formatierung einzelner Datenelemente oder Sammlungen von Datenelementen zu ermöglichen, wie z. B. ListBox und ListView. Sortier-, Filter- und Gruppenansichten können über die Daten generiert werden.

Die Datenbindung in WPF bietet gegenüber herkömmlichen Modellen mehrere Vorteile, einschließlich der inhärenten Unterstützung für die Datenbindung durch eine breite Palette von Eigenschaften, flexible UI-Darstellung von Daten und eine saubere Trennung von Geschäftslogik von der Benutzeroberfläche.

In diesem Artikel werden zunächst grundlegende Konzepte für die WPF-Datenbindung erläutert und dann die Verwendung der Binding Klasse und anderer Features der Datenbindung behandelt.

Was ist Datenbindung?

Die Datenbindung ist der Prozess, der eine Verbindung zwischen der App-UI und den angezeigten Daten herstellt. Wenn die Bindung über die richtigen Einstellungen verfügt und die Daten die richtigen Benachrichtigungen enthalten, werden die Elemente, die an die Daten gebunden sind, automatisch aktualisiert, sobald die Daten ihren Wert ändern. Die Datenbindung kann auch bedeuten, dass, wenn sich eine äußere Darstellung der Daten in einem Element ändert, die zugrunde liegenden Daten automatisch aktualisiert werden können, um die Änderung widerzuspiegeln. Wenn der Benutzer beispielsweise den Wert in einem TextBox Element bearbeitet, wird der zugrunde liegende Datenwert automatisch aktualisiert, um diese Änderung widerzuspiegeln.

Eine typische Verwendung der Datenbindung besteht darin, Server- oder lokale Konfigurationsdaten in Formularen oder anderen UI-Steuerelementen zu platzieren. In WPF wird dieses Konzept erweitert, um eine breite Palette von Eigenschaften an verschiedene Arten von Datenquellen zu binden. In WPF können Abhängigkeitseigenschaften von Elementen an .NET-Objekte (einschließlich ADO.NET Objekte oder Objekte gebunden werden, die Webdiensten und Webeigenschaften zugeordnet sind) und XML-Daten.

Grundlegende Konzepte für die Datenbindung

Unabhängig davon, welches Element Sie binden und welche Art ihre Datenquelle hat, folgt jede Bindung immer dem Modell, das in der folgenden Abbildung dargestellt wird.

Diagramm, das das grundlegende Datenbindungsmodell zeigt.

Wie die Abbildung zeigt, ist die Datenbindung im Wesentlichen die Brücke zwischen Ihrem Bindungsziel und Ihrer Bindungsquelle. Die Abbildung zeigt die folgenden grundlegenden WPF-Datenbindungskonzepte:

  • In der Regel verfügt jede Bindung über vier Komponenten:

    • Ein Bindungszielobjekt.
    • Eine Zieleigenschaft.
    • Eine Bindungsquelle.
    • Ein Pfad zum Wert in der zu verwendenden Bindungsquelle.

    Wenn Sie z. B. den Inhalt einer TextBox Eigenschaft an die Employee.Name Eigenschaft gebunden haben, würden Sie ihre Bindung wie in der folgenden Tabelle einrichten:

    Konfiguration Wert
    Ziel TextBox
    Target-Eigenschaft Text
    Source-Objekt Employee
    Quellobjektwertpfad Name
  • Die Zieleigenschaft muss eine Abhängigkeitseigenschaft sein.

    Die meisten UIElement Eigenschaften sind Abhängigkeitseigenschaften und die meisten Abhängigkeitseigenschaften, außer schreibgeschützten, unterstützen standardmäßig die Datenbindung. Nur von DependencyObject Typen abgeleitete Typen können Abhängigkeitseigenschaften definieren. Alle UIElement Typen werden von DependencyObject.

  • Bindungsquellen sind nicht auf benutzerdefinierte .NET-Objekte beschränkt.

    Obwohl nicht in der Abbildung gezeigt, sollte darauf hingewiesen werden, dass das Bindungsquellobjekt nicht auf ein benutzerdefiniertes .NET-Objekt beschränkt ist. WPF-Datenbindung unterstützt Daten in Form von .NET-Objekten, XML und sogar XAML-Elementobjekten. Um einige Beispiele zu geben, kann es sich bei der Bindungsquelle um ein UIElement beliebiges Listenobjekt, ein ADO.NET- oder Webdienst-Objekt oder um einen XmlNode handeln, der Ihre XML-Daten enthält. Weitere Informationen finden Sie in der Übersicht über Bindungsquellen.

Es ist wichtig zu beachten, dass Sie beim Einrichten einer Bindung ein Bindungsziel an eine Bindungsquelle binden. Wenn Sie z. B. einige zugrunde liegende XML-Daten in einer ListBox Using-Datenbindung anzeigen, binden Sie Ihre ListBox Daten an die XML-Daten.

Um eine Bindung herzustellen, verwenden Sie das Binding Objekt. Im restlichen Artikel werden viele der Konzepte erläutert, die mit den Eigenschaften und der Verwendung des Binding Objekts verknüpft sind.

Datenkontext

Wenn die Datenbindung für XAML-Elemente deklariert wird, lösen sie die Datenbindung, indem sie ihre unmittelbare DataContext Eigenschaft betrachten. Der Datenkontext ist in der Regel das Bindungsquellobjekt für die Auswertung des Bindungsquellwertpfads . Sie können dieses Verhalten in der Bindung außer Kraft setzen und einen bestimmten Bindungsquellobjektwert festlegen. Wenn die DataContext Eigenschaft für das Objekt, das die Bindung hostet, nicht festgelegt ist, wird die Eigenschaft des DataContext übergeordneten Elements überprüft usw. bis zum Stamm der XAML-Objektstruktur. Kurz gesagt, der Zum Auflösen der Bindung verwendete Datenkontext wird vom übergeordneten Objekt geerbt, es sei denn, der explizit für das Objekt festgelegt wird.

Bindungen können so konfiguriert werden, dass sie mit einem bestimmten Objekt aufgelöst werden, anstatt den Datenkontext für die Bindungsauflösung zu verwenden. Die direkte Angabe eines Quellobjekts wird verwendet, wenn Sie z. B. die Vordergrundfarbe eines Objekts an die Hintergrundfarbe eines anderen Objekts binden. Der Datenkontext ist nicht erforderlich, da die Bindung zwischen diesen beiden Objekten aufgelöst wird. Umgekehrt verwenden Bindungen, die nicht an bestimmte Quellobjekte gebunden sind, die Datenkontextauflösung.

Wenn sich die DataContext Eigenschaft ändert, werden alle Bindungen, die vom Datenkontext betroffen sein könnten, neu ausgewertet.

Richtung des Datenflusses

Wie durch den Pfeil in der vorherigen Abbildung angegeben, kann der Datenfluss einer Bindung vom Bindungsziel zur Bindungsquelle erfolgen (z. B. ändert sich der Quellwert, wenn ein Benutzer den Wert einer TextBox bearbeitet) und/oder von der Bindungsquelle zum Bindungsziel (z. B. wird der Inhalt der TextBox durch Änderungen in der Bindungsquelle aktualisiert), wenn die Bindungsquelle die richtigen Benachrichtigungen bereitstellt.

Möglicherweise möchten Sie, dass Ihre App Benutzern das Ändern der Daten und die Weitergabe an das Quellobjekt ermöglicht. Oder Sie möchten es Benutzern nicht ermöglichen, die Quelldaten zu aktualisieren. Sie können den Datenfluss steuern, indem Sie Binding.Mode festlegen.

In dieser Abbildung sind die verschiedenen Datentypen des Datenflusses dargestellt:

Datenbindungsdatenfluss

  • OneWay Durch bindung werden Änderungen an der Quelleigenschaft automatisch aktualisiert, aber Änderungen an der Zieleigenschaft werden nicht an die Quelleigenschaft weitergegeben. Dieser Bindungstyp ist geeignet, wenn das gebundene Steuerelement implizit schreibgeschützt ist. Sie können beispielsweise eine Bindung an eine Quelle wie einen Aktienticker vornehmen, oder Ihre Zieleigenschaft hat möglicherweise keine Steuerelementschnittstelle für Änderungen, wie etwa eine datengebundene Hintergrundfarbe einer Tabelle. Wenn die Änderungen der Zieleigenschaft nicht überwacht werden müssen, vermeidet die Verwendung des OneWay Bindungsmodus den Aufwand des TwoWay Bindungsmodus.

  • TwoWay Bindung bewirkt, dass Änderungen entweder an der Quelleigenschaft oder der Zieleigenschaft die jeweils andere Eigenschaft automatisch aktualisieren. Diese Art von Bindung eignet sich für bearbeitbare Formulare oder andere vollständig interaktive Benutzeroberflächenszenarien. Die meisten Eigenschaften haben standardmäßig die OneWay-Bindung, aber einige Abhängigkeitseigenschaften (typischerweise Eigenschaften von benutzerbearbeitbaren Steuerungselementen wie TextBox.Text und CheckBox.IsChecked) weisen die TwoWay-Bindung auf.

    Eine programmgesteuerte Methode zum Bestimmen, ob eine Abhängigkeitseigenschaft standardmäßig unidirektionale oder bidirektionale Bindungen enthält, besteht darin, die Eigenschaftsmetadaten abzurufen.DependencyProperty.GetMetadata Der Rückgabetyp dieser Methode ist PropertyMetadata, der keine Metadaten zur Bindung enthält. Wenn dieser Typ in den abgeleiteten FrameworkPropertyMetadata konvertiert werden kann, kann der boolesche Wert der FrameworkPropertyMetadata.BindsTwoWayByDefaultEigenschaft überprüft werden. Das folgende Codebeispiel veranschaulicht das Abrufen der Metadaten für die TextBox.Text Eigenschaft:

    public static void PrintMetadata()
    {
        // Get the metadata for the property
        PropertyMetadata metadata = TextBox.TextProperty.GetMetadata(typeof(TextBox));
    
        // Check if metadata type is FrameworkPropertyMetadata
        if (metadata is FrameworkPropertyMetadata frameworkMetadata)
        {
            System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:");
            System.Diagnostics.Debug.WriteLine($"  BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}");
            System.Diagnostics.Debug.WriteLine($"  IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}");
            System.Diagnostics.Debug.WriteLine($"        AffectsArrange: {frameworkMetadata.AffectsArrange}");
            System.Diagnostics.Debug.WriteLine($"        AffectsMeasure: {frameworkMetadata.AffectsMeasure}");
            System.Diagnostics.Debug.WriteLine($"         AffectsRender: {frameworkMetadata.AffectsRender}");
            System.Diagnostics.Debug.WriteLine($"              Inherits: {frameworkMetadata.Inherits}");
        }
    
        /*  Displays:
         *  
         *  TextBox.Text property metadata:
         *    BindsTwoWayByDefault: True
         *    IsDataBindingAllowed: True
         *          AffectsArrange: False
         *          AffectsMeasure: False
         *           AffectsRender: False
         *                Inherits: False
        */
    }
    
    Public Shared Sub PrintMetadata()
    
        Dim metadata As PropertyMetadata = TextBox.TextProperty.GetMetadata(GetType(TextBox))
        Dim frameworkMetadata As FrameworkPropertyMetadata = TryCast(metadata, FrameworkPropertyMetadata)
    
        If frameworkMetadata IsNot Nothing Then
    
            System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:")
            System.Diagnostics.Debug.WriteLine($"  BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}")
            System.Diagnostics.Debug.WriteLine($"  IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}")
            System.Diagnostics.Debug.WriteLine($"        AffectsArrange: {frameworkMetadata.AffectsArrange}")
            System.Diagnostics.Debug.WriteLine($"        AffectsMeasure: {frameworkMetadata.AffectsMeasure}")
            System.Diagnostics.Debug.WriteLine($"         AffectsRender: {frameworkMetadata.AffectsRender}")
            System.Diagnostics.Debug.WriteLine($"              Inherits: {frameworkMetadata.Inherits}")
    
            '  Displays:
            '
            '  TextBox.Text property metadata:
            '    BindsTwoWayByDefault: True
            '    IsDataBindingAllowed: True
            '          AffectsArrange: False
            '          AffectsMeasure: False
            '           AffectsRender: False
            '                Inherits: False
        End If
    
    
    End Sub
    
  • OneWayToSource ist das Umgekehrte der OneWay Bindung. Sie aktualisiert die Quelleigenschaft, wenn sich die Zieleigenschaft ändert. Ein Beispielszenario ist, wenn Sie den Quellwert nur aus der Benutzeroberfläche neu bewerten müssen.

  • Nicht in der Abbildung dargestellt ist die OneTime Bindung, wodurch die Quelleigenschaft die Zieleigenschaft initialisiert, aber nachfolgende Änderungen nicht propagiert werden. Wenn sich der Datenkontext ändert oder sich das Objekt im Datenkontext ändert, wird die Änderung nicht in der Zieleigenschaft widergespiegelt. Diese Art von Bindung ist geeignet, wenn entweder eine Momentaufnahme des aktuellen Zustands geeignet ist oder die Daten wirklich statisch sind. Diese Bindungsart ist auch hilfreich, wenn Sie Ihre Zieleigenschaft mit einem Bestimmten Wert aus einer Quelleigenschaft initialisieren möchten und der Datenkontext im Voraus nicht bekannt ist. Dieser Modus ist im Wesentlichen eine einfachere Form der OneWay Bindung, die eine bessere Leistung in Fällen bietet, in denen sich der Quellwert nicht ändert.

Um Quelländerungen zu erkennen (gilt für OneWay und TwoWay Bindungen), muss die Quelle einen geeigneten Mechanismus für Eigenschaftenänderungsbenachrichtigungen implementieren, z.B. INotifyPropertyChanged. Siehe How to: Implement property change notification (.NET Framework) für ein Beispiel einer INotifyPropertyChanged Implementierung.

Die Binding.Mode Eigenschaft enthält weitere Informationen zu Bindungsmodi und ein Beispiel zum Angeben der Richtung einer Bindung.

Was löst Quellupdates aus

Bindungen, die TwoWay auf Änderungen in der Zieleigenschaft lauschen oder OneWayToSource diese an die Quelle weitergeben, die als Aktualisierung der Quelle bezeichnet werden. Beispielsweise können Sie den Text eines TextBox-Steuerelements bearbeiten, um den zugrunde liegenden Quellwert zu ändern.

Wird der Quellwert jedoch aktualisiert, während Sie den Text bearbeiten oder nachdem Sie die Bearbeitung des Texts abgeschlossen haben und das Steuerelement den Fokus verliert? Die Binding.UpdateSourceTrigger Eigenschaft bestimmt, was die Aktualisierung der Quelle auslöst. Die Punkte der Nach-rechts-Pfeile in der folgenden Abbildung veranschaulichen die Rolle der Binding.UpdateSourceTrigger Eigenschaft.

Diagramm, das die Rolle der UpdateSourceTrigger-Eigenschaft zeigt.

Wenn der UpdateSourceTrigger Wert lautet UpdateSourceTrigger.PropertyChanged, wird der wert, auf den der Pfeil TwoWay nach rechts zeigt, oder die OneWayToSource Bindungen aktualisiert, sobald sich die Zieleigenschaft ändert. Wenn der UpdateSourceTrigger Wert jedoch lautet LostFocus, wird dieser Wert nur mit dem neuen Wert aktualisiert, wenn die Zieleigenschaft den Fokus verliert.

Ähnlich wie bei der Mode Eigenschaft weisen unterschiedliche Abhängigkeitseigenschaften unterschiedliche Standardwerte UpdateSourceTrigger auf. Der Standardwert für die meisten Abhängigkeitseigenschaften ist PropertyChanged, was bewirkt, dass der Wert der Quelleigenschaft sofort geändert wird, wenn der Zieleigenschaftswert geändert wird. Sofortige Änderungen sind für CheckBox andere einfache Steuerelemente in Ordnung. Bei Textfeldern kann die Aktualisierung nach jedem Tastenanschlag jedoch die Leistung beeinträchtigen und dem Benutzer die übliche Möglichkeit zum Rücktasten und Beheben von Eingabefehlern verweigern, bevor ein Commit für den neuen Wert durchgeführt wird. Die TextBox.Text Eigenschaft hat beispielsweise standardmäßig den UpdateSourceTrigger Wert von LostFocus, was bewirkt, dass der Quellwert nur geändert wird, wenn das Steuerelement den Fokus verliert, nicht wenn die TextBox.Text Eigenschaft geändert wird. Informationen zum Suchen des Standardwerts einer Abhängigkeitseigenschaft finden Sie auf der UpdateSourceTrigger Eigenschaftenseite.

Die folgende Tabelle bietet ein Beispielszenario für jeden UpdateSourceTrigger-Wert unter Verwendung von TextBox als Beispiel.

UpdateSourceTrigger-Wert Wenn der Quellwert aktualisiert wird Beispielszenario für TextBox
LostFocus (Standard für TextBox.Text) Wenn das TextBox-Steuerelement den Fokus verliert. Ein TextBox-Objekt, das der Validierungslogik zugeordnet ist (siehe Datenüberprüfung unten).
PropertyChanged Während der Eingabe in das TextBox. TextBox-Steuerelemente in einem Chatroomfenster.
Explicit Wenn die App UpdateSource aufruft. TextBox-Steuerelemente in einem bearbeitbaren Formular (aktualisiert die Quellwerte nur, wenn der Benutzer die Schaltfläche "Absenden" drückt).

Ein Beispiel finden Sie unter So steuern Sie, wann der Text des TextBox die Quelle aktualisiert (.NET Framework).

Beispiel für datenbindung

Ein Beispiel für die Datenbindung sehen Sie sich die folgende App-UI aus der "Data Binding Demo" an, die eine Liste der Auktionselemente anzeigt.

Screenshot des Datenbindungsbeispiels

Die App veranschaulicht die folgenden Features der Datenbindung:

  • Der Inhalt des ListBox-Objekts ist an eine Sammlung von AuctionItem-Objekten gebunden. Ein AuctionItem-Objekt verfügt über Eigenschaften wie Description, StartPrice, StartDate, Category und SpecialFeatures.

  • Die Daten (AuctionItem-Objekte ) werden mithilfe von Vorlagen angezeigt, sodass die Beschreibung und der aktuelle Preis für jedes Objekt dargestellt werden. Die Vorlage wird mithilfe einer DataTemplate. Darüber hinaus hängt das Erscheinungsbild jedes Elements vom Wert "SpecialFeatures " des angezeigten Auktionsobjekts ab. Wenn der Wert "SpecialFeatures " des Auktionselements"Color" lautet, weist das Element einen blauen Rahmen auf. Wenn der Wert "Hervorheben" lautet, weist das Element einen orangefarbenen Rahmen und einen Stern auf. Der Abschnitt „Daten-Templating“ enthält Informationen über Daten-Templating.

  • Der Benutzer kann die Daten mithilfe der CheckBoxes bereitgestellten Daten gruppieren, filtern oder sortieren. In der obigen Abbildung sind die Optionen Nach Kategorie gruppieren und Nach Kategorie und Datum sortierenCheckBoxes ausgewählt. Möglicherweise haben Sie bemerkt, dass die Daten basierend auf der Kategorie des Produkts gruppiert sind und der Kategoriename alphabetisch sortiert ist. Es ist schwierig, aus dem Bild zu bemerken, aber die Elemente werden auch nach dem Startdatum innerhalb jeder Kategorie sortiert. Die Sortierung erfolgt mithilfe einer Sammlungsansicht. Im Abschnitt "Bindung an Sammlungen " werden Sammlungsansichten erläutert.

  • Wenn der Benutzer ein Element auswählt, werden die ContentControl Details des ausgewählten Elements angezeigt. Diese Erfahrung wird als Master-Detail-Szenario bezeichnet. Der Abschnitt " Master-Detail-Szenario " enthält Informationen zu diesem Bindungstyp.

  • Der Typ der StartDate-Eigenschaft lautet DateTime, die ein Datum zurückgibt, das die Uhrzeit in millisekunden enthält. In dieser App wurde ein benutzerdefinierter Konverter verwendet, sodass eine kürzere Datumszeichenfolge angezeigt wird. Der Abschnitt " Datenkonvertierung " enthält Informationen zu Konvertern.

Wenn der Benutzer die Schaltfläche " Produkt hinzufügen " auswählt, wird das folgende Formular angezeigt.

Seite

Der Benutzer kann die Felder im Formular bearbeiten, die Produktliste mit der kurzen oder detaillierten Vorschau anzeigen und Submit auswählen, um die neue Produktliste hinzuzufügen. Alle vorhandenen Gruppierungs-, Filter- und Sortiereinstellungen gelten für den neuen Eintrag. In diesem Fall wird das in das obige Bild eingegebene Element als zweites Element in der Kategorie "Computer " angezeigt.

In dieser Abbildung ist die Im StartdatumTextBox angegebene Überprüfungslogik nicht dargestellt. Wenn der Nutzer ein ungültiges Datum (ungültige Formatierung oder ein vergangenes Datum) eingibt, wird er mit einem ToolTip und einem roten Ausrufezeichen neben dem TextBox benachrichtigt. Im Abschnitt "Datenüberprüfung " wird erläutert, wie Sie Validierungslogik erstellen.

Bevor wir die verschiedenen oben beschriebenen Features der Datenbindung eingehen, werden wir zunächst die grundlegenden Konzepte diskutieren, die für das Verständnis der WPF-Datenbindung von entscheidender Bedeutung sind.

Erstellen einer Bindung

Wenn Sie einige der in den vorherigen Abschnitten erläuterten Konzepte neu erstellen möchten, richten Sie eine Bindung mithilfe des Binding Objekts ein, und jede Bindung verfügt in der Regel über vier Komponenten: ein Bindungsziel, eine Zieleigenschaft, eine Bindungsquelle und einen Pfad zum zu verwendenden Quellwert. In diesem Abschnitt wird erläutert, wie Sie eine Bindung einrichten.

Bindungsquellen sind an das aktive DataContext Element gebunden. Elemente erben ihre DataContext automatisch, wenn sie nicht explizit definiert wurden.

Betrachten Sie das folgende Beispiel, in dem das Bindungsquellobjekt eine Klasse mit dem Namen MyData ist, die im SDKSample-Namespace definiert ist. Zu Demonstrationszwecken verfügt MyData über eine Zeichenfolgeneigenschaft namens ColorName , deren Wert auf "Red" festgelegt ist. Daher generiert dieses Beispiel eine Schaltfläche mit einem roten Hintergrund.

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:c="clr-namespace:SDKSample">
    <DockPanel.Resources>
        <c:MyData x:Key="myDataSource"/>
    </DockPanel.Resources>
    <DockPanel.DataContext>
        <Binding Source="{StaticResource myDataSource}"/>
    </DockPanel.DataContext>
    <Button Background="{Binding Path=ColorName}"
            Width="150" Height="30">
        I am bound to be RED!
    </Button>
</DockPanel>

Weitere Informationen zur Bindungsdeklarationssyntax und Beispielen zum Einrichten einer Bindung im Code finden Sie in der Übersicht über Bindungsdeklarationen.

Wenn wir dieses Beispiel auf unser Basisdiagramm anwenden, sieht die resultierende Abbildung wie folgt aus. Diese Abbildung beschreibt eine OneWay Bindung, da die Background-Eigenschaft standardmäßig die Bindung mit OneWay unterstützt.

Diagramm, das die Datenbindung der Hintergrund-Eigenschaft zeigt.

Sie fragen sich vielleicht, warum diese Bindung funktioniert, obwohl die ColorName-Eigenschaft vom Typ Zeichenfolge ist, während die Background Eigenschaft vom Typ Brushist. Diese Bindung verwendet die Standardtypkonvertierung, die im Abschnitt "Datenkonvertierung " erläutert wird.

Angeben der Bindungsquelle

Beachten Sie, dass im vorherigen Beispiel die Bindungsquelle durch Festlegen der DockPanel.DataContext-Eigenschaft angegeben wird. Erbt Button dann den DataContext Wert vom übergeordneten Element.DockPanel Zum Wiederholen ist das Bindungsquellobjekt eine der vier erforderlichen Komponenten einer Bindung. Ohne das Bindungsquellobjekt, das angegeben wird, würde die Bindung also nichts tun.

Es gibt mehrere Möglichkeiten zum Angeben des Bindungsquellobjekts. Die Verwendung der DataContext Eigenschaft für ein übergeordnetes Element ist nützlich, wenn Sie mehrere Eigenschaften an dieselbe Quelle binden. Manchmal ist es jedoch sinnvoller, die Bindungsquelle für einzelne Bindungsdeklarationen anzugeben. Im vorherigen Beispiel können Sie anstelle der DataContext Eigenschaft die Bindungsquelle angeben, indem Sie die Binding.Source Eigenschaft direkt auf die Bindungsdeklaration der Schaltfläche festlegen, wie im folgenden Beispiel gezeigt.

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:c="clr-namespace:SDKSample">
    <DockPanel.Resources>
        <c:MyData x:Key="myDataSource"/>
    </DockPanel.Resources>
    <Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}"
            Width="150" Height="30">
        I am bound to be RED!
    </Button>
</DockPanel>

Abgesehen davon, dass die DataContext Eigenschaft für ein Element direkt festgelegt wird, erben Sie den DataContext Wert von einem Vorgänger (z. B. die Schaltfläche im ersten Beispiel) und explizit die Bindungsquelle durch Festlegen der Binding.Source Eigenschaft für die Bindung (z. B. die Schaltfläche im letzten Beispiel), können Sie auch die Binding.ElementName Eigenschaft oder die Binding.RelativeSource Eigenschaft verwenden, um die Bindungsquelle anzugeben. Die ElementName Eigenschaft ist nützlich, wenn Sie an andere Elemente in Ihrer App binden, z. B. wenn Sie einen Schieberegler verwenden, um die Breite einer Schaltfläche anzupassen. Die Eigenschaft RelativeSource ist nützlich, wenn die Bindung in einem ControlTemplate oder einem Style angegeben wird. Weitere Informationen finden Sie in der Übersicht über Bindungsquellen.

Angeben des Pfads zum Wert

Wenn es sich bei der Bindungsquelle um ein Objekt handelt, verwenden Sie die Binding.Path Eigenschaft, um den Wert anzugeben, der für die Bindung verwendet werden soll. Wenn Sie eine Bindung an XML-Daten ausführen, verwenden Sie die Binding.XPath Eigenschaft, um den Wert anzugeben. In einigen Fällen kann es anwendbar sein, die Path Eigenschaft auch dann zu verwenden, wenn Ihre Daten XML sind. Wenn Sie beispielsweise auf die Name-Eigenschaft eines zurückgegebenen XmlNode (als Ergebnis einer XPath-Abfrage) zugreifen möchten, sollten Sie die Path-Eigenschaft zusätzlich zur XPath-Eigenschaft verwenden.

Weitere Informationen finden Sie unter den Path Und XPath Eigenschaften.

Obwohl wir betont haben, dass der Path zu verwendende Wert eine der vier erforderlichen Komponenten einer Bindung ist, in den Szenarien, die Sie an ein gesamtes Objekt binden möchten, entspricht der zu verwendende Wert dem Bindungsquellobjekt. In diesen Fällen gilt es, kein Path anzugeben. Betrachten Sie das folgende Beispiel.

<ListBox ItemsSource="{Binding}"
         IsSynchronizedWithCurrentItem="true"/>

Im obigen Beispiel wird die leere Bindungssyntax {Binding} verwendet. In diesem Fall erbt der ListBox DataContext von einem übergeordneten DockPanel-Element (nicht in diesem Beispiel dargestellt). Wenn der Pfad nicht angegeben ist, besteht die Standardeinstellung darin, eine Bindung an das gesamte Objekt zu erstellen. Anders ausgedrückt: In diesem Beispiel wurde der Pfad weggelassen, da wir die ItemsSource Eigenschaft an das gesamte Objekt binden. (Eine ausführliche Erläuterung finden Sie im Abschnitt "Bindung an Sammlungen ".)

Abgesehen von der Bindung an eine Auflistung ist dieses Szenario auch hilfreich, wenn Sie eine Bindung an ein gesamtes Objekt anstelle einer einzigen Eigenschaft eines Objekts durchführen möchten. Wenn ihr Quellobjekt z. B. vom Typ Stringist, können Sie einfach eine Bindung an die Zeichenfolge selbst erstellen. Ein weiteres häufiges Szenario ist, wenn Sie ein Element an ein Objekt mit mehreren Eigenschaften binden möchten.

Möglicherweise müssen Sie benutzerdefinierte Logik anwenden, damit die Daten für Ihre gebundene Zieleigenschaft aussagekräftig sind. Die benutzerdefinierte Logik kann sich in Form eines benutzerdefinierten Konverters befinden, wenn keine Standardtypkonvertierung vorhanden ist. Informationen zu Konvertern finden Sie unter "Datenkonvertierung ".

Binding und BindingExpression

Bevor Sie in andere Features und Verwendungen der Datenbindung eingehen, ist es hilfreich, die BindingExpression Klasse einzuführen. Wie Sie in früheren Abschnitten gesehen haben, ist die Binding Klasse die allgemeine Klasse für die Deklaration einer Bindung. Sie stellt viele Eigenschaften bereit, mit denen Sie die Merkmale einer Bindung angeben können. Eine verwandte Klasse ist das zugrunde liegende Objekt, BindingExpressiondas die Verbindung zwischen der Quelle und dem Ziel verwaltet. Eine Verbindung enthält alle Informationen, die über mehrere Ausdrucksbindungen hinweg geteilt werden können. Ein BindingExpression ist ein Instanzausdruck, der nicht freigegeben werden kann und alle Instanzinformationen des Binding beinhaltet.

Betrachten Sie das folgende Beispiel, bei dem myDataObject es sich um eine Instanz der MyData Klasse handelt, myBinding das Quellobjekt Binding und MyData eine definierte Klasse, die eine Zeichenfolgeneigenschaft mit dem Namen ColorNameenthält. In diesem Beispiel wird der Textinhalt von myText, einer Instanz von TextBlock, mit ColorName verbunden.

// Make a new source
var myDataObject = new MyData();
var myBinding = new Binding("ColorName")
{
    Source = myDataObject
};

// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
' Make a New source
Dim myDataObject As New MyData
Dim myBinding As New Binding("ColorName")
myBinding.Source = myDataObject

' Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding)

Sie können dasselbe myBinding-Objekt verwenden, um andere Bindungen zu erstellen. Sie können beispielsweise das myBinding-Objekt verwenden, um den Textinhalt eines Kontrollkästchens an ColorName zu binden. In diesem Szenario werden zwei Instanzen von BindingExpression, die das myBinding-Objekt teilen, vorhanden sein.

Ein BindingExpression Objekt wird durch Aufrufen GetBindingExpression eines datengebundenen Objekts zurückgegeben. Die folgenden Artikel veranschaulichen einige der Verwendungen der BindingExpression Klasse:

Datenkonvertierung

Im Abschnitt "Bindung erstellen " ist die Schaltfläche rot, da die Background Eigenschaft an eine Zeichenfolgeneigenschaft mit dem Wert "Red" gebunden ist. Der Zeichenfolgenwert funktioniert, da ein Typkonverter beim Brush Typ vorhanden ist, der den Zeichenfolgenwert in ein Brush umwandelt.

Das Hinzufügen dieser Informationen zur Abbildung im Abschnitt " Erstellen einer Bindung " sieht wie folgt aus.

Diagramm, das die Standardeigenschaft für die Datenbindung zeigt.

Was geschieht jedoch, wenn anstelle einer Eigenschaft vom Typ Zeichenfolge das Bindungsquellobjekt eine Color-Eigenschaft vom Typ Colorhat? ** In diesem Fall müssten Sie, damit die Bindung funktioniert, zuerst den Wert der Color-Eigenschaft in ein Format konvertieren, das die Background Eigenschaft akzeptiert. Sie müssen einen benutzerdefinierten Konverter erstellen, indem Sie die IValueConverter Schnittstelle implementieren, wie im folgenden Beispiel gezeigt.

[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Color color = (Color)value;
        return new SolidColorBrush(color);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        Dim color As Color = CType(value, Color)
        Return New SolidColorBrush(color)
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Return Nothing
    End Function
End Class

Weitere Informationen finden Sie unter IValueConverter.

Jetzt wird der benutzerdefinierte Konverter anstelle der Standardkonvertierung verwendet, und unser Diagramm sieht wie folgt aus.

Diagramm, das den benutzerdefinierten Datenbindungskonverter zeigt.

Um dies zu wiederholen, können Standardkonvertierungen aufgrund von Typkonvertern verfügbar sein, die in dem Typ vorhanden sind, an den gebunden wird. Dieses Verhalten hängt davon ab, welche Typkonverter im Ziel verfügbar sind. Erstellen Sie im Zweifelsfall ihren eigenen Konverter.

Im Folgenden sind einige typische Szenarien aufgeführt, in denen es sinnvoll ist, einen Datenkonverter zu implementieren:

  • Ihre Daten sollten je nach Kultur unterschiedlich angezeigt werden. Sie können z. B. einen Währungskonverter oder einen Kalenderdatums-/Uhrzeitkonverter basierend auf den Konventionen implementieren, die in einer bestimmten Kultur verwendet werden.

  • Die verwendeten Daten sollen nicht unbedingt den Textwert einer Eigenschaft ändern, sondern stattdessen einen anderen Wert ändern, z. B. die Quelle für ein Bild oder die Farbe oder das Format des Anzeigetexts. Konverter können in dieser Instanz verwendet werden, indem die Bindung einer Eigenschaft konvertiert wird, die möglicherweise nicht geeignet ist, z. B. das Binden eines Textfelds an die Background-Eigenschaft einer Tabellenzelle.

  • Mehrere Steuerelemente oder mehrere Eigenschaften von Steuerelementen sind an dieselben Daten gebunden. In diesem Fall zeigt die primäre Bindung möglicherweise nur den Text an, während andere Bindungen bestimmte Anzeigeprobleme behandeln, aber weiterhin dieselbe Bindung wie Quellinformationen verwenden.

  • Eine Zieleigenschaft verfügt über eine Sammlung von Verknüpfungen, die als MultiBinding bezeichnet wird. Verwenden Sie für MultiBinding einen benutzerdefinierten IMultiValueConverter, um einen endgültigen Wert aus den Werten der Bindungen zu erzeugen. Beispielsweise können Farben aus roten, blauen und grünen Werten berechnet werden, bei denen es sich um Werte aus demselben oder unterschiedlichen Bindungsquellenobjekten handeln kann. Für Beispiele und Informationen siehe MultiBinding.

Verbindung mit Sammlungen

Ein Bindungsquellobjekt kann entweder als einzelnes Objekt behandelt werden, dessen Eigenschaften Daten enthalten, oder als Eine Datensammlung von polymorphen Objekten, die häufig gruppiert sind (z. B. das Ergebnis einer Abfrage zu einer Datenbank). Bisher haben wir nur die Bindung an einzelne Objekte diskutiert. Die Bindung an eine Datensammlung ist jedoch ein häufiges Szenario. Ein gängiges Szenario ist z. B. die Verwendung eines ItemsControl Solchen, ListViewListBoxoder TreeView das Anzeigen einer Datensammlung, z. B. in der App, die im Abschnitt "Datenbindung" angezeigt wird.

Glücklicherweise gilt unser Basisdiagramm noch. Wenn Sie ItemsControl an eine Sammlung binden, sieht das Diagramm wie folgt aus.

Diagramm, das das ItemsControl-Objekt für die Datenbindung zeigt.

Wie in diesem Diagramm gezeigt, ist die ItemsControl.ItemsSource-Eigenschaft, die verwendet werden soll, um ein ItemsControl-Objekt an eine Sammlung zu binden. Sie können sich ItemsSource als den Inhalt von ItemsControl vorstellen. Die Bindung ist OneWay, weil die ItemsSource-Eigenschaft standardmäßig das OneWay-Binding unterstützt.

So implementieren Sie Sammlungen

Sie können über jede Sammlung enumerieren, die die IEnumerable-Schnittstelle implementiert. Um dynamische Bindungen einzurichten, damit die Benutzeroberfläche nach Einfügungen oder Löschungen in der Sammlung automatisch aktualisiert wird, muss die Sammlung die INotifyCollectionChanged-Schnittstelle implementieren. Diese Schnittstelle macht ein Ereignis verfügbar, das bei jeder Änderung der zugrunde liegenden Auflistung ausgelöst werden soll.

WPF stellt die Klasse ObservableCollection<T> bereit, die eine integrierte Implementierung einer Datensammlung ist und die INotifyCollectionChanged Schnittstelle bereitstellt. Um das Übertragen von Datenwerten von Quellobjekten zu Zielen vollständig zu unterstützen, muss jedes Objekt in Ihrer Auflistung, das bindbare Eigenschaften unterstützt, auch die INotifyPropertyChanged Schnittstelle implementieren. Weitere Informationen finden Sie in der Übersicht über Bindungsquellen.

Bevor Sie eine eigene Sammlung implementieren, sollten Sie erwägen, ObservableCollection<T> oder eine der bestehenden Sammlungsklassen wie List<T>, Collection<T> und BindingList<T> zu verwenden. Wenn Sie über ein erweitertes Szenario verfügen und Ihre eigene Sammlung implementieren möchten, sollten Sie die Verwendung in IListBetracht ziehen, die eine nicht generische Auflistung von Objekten bereitstellt, auf die vom Index einzeln zugegriffen werden kann, und bietet somit die beste Leistung.

Sammlungsansichten

Sobald Ihr ItemsControl an eine Datensammlung gebunden ist, möchten Sie möglicherweise die Daten sortieren, filtern oder gruppieren. Dazu verwenden Sie Sammlungsansichten, bei denen es sich um Klassen handelt, die die ICollectionView Schnittstelle implementieren.

Was sind Sammlungsansichten?

Eine Sammlungsansicht ist eine Ebene über einer Bindungsquellauflistung, mit der Sie die Quellauflistung basierend auf Sortier-, Filter- und Gruppenabfragen navigieren und anzeigen können, ohne die zugrunde liegende Quellauflistung selbst ändern zu müssen. Eine Sammlungsansicht verwaltet auch einen Zeiger auf das aktuelle Element in der Sammlung. Wenn die Quellauflistung die INotifyCollectionChanged Schnittstelle implementiert, werden die vom CollectionChanged Ereignis ausgelösten Änderungen an die Ansichten weitergegeben.

Da Ansichten die zugrunde liegenden Quellauflistungen nicht ändern, kann jede Quellauflistung mehrere Ansichten zugeordnet sein. Beispielsweise verfügen Sie möglicherweise über eine Auflistung von Task-Objekten . Mit der Verwendung von Ansichten können Sie dieselben Daten auf unterschiedliche Weise anzeigen. Beispielsweise möchten Sie auf der linken Seite der Seite möglicherweise Aufgaben nach Priorität sortiert und auf der rechten Seite nach Bereich gruppiert anzeigen.

So erstellen Sie eine Ansicht

Eine Möglichkeit zum Erstellen und Verwenden einer Ansicht besteht darin, das Ansichtsobjekt direkt zu instanziieren und dann als Bindungsquelle zu verwenden. Betrachten Sie z. B. die ", die im Abschnitt "Was ist Datenbindung" angezeigt wird. Die App wird so implementiert, dass die ListBox an eine Ansicht über die Datenkollektion und nicht direkt an die Datenkollektion gebunden wird. Das folgende Beispiel wird aus der extrahiert. Die CollectionViewSource-Klasse ist der XAML-Proxy einer Klasse, die von CollectionView erbt. In diesem bestimmten Beispiel ist die Source Ansicht an die AuctionItems-Auflistung (vom Typ ObservableCollection<T>) des aktuellen App-Objekts gebunden.

<Window.Resources>
    <CollectionViewSource 
      Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"   
      x:Key="listingDataView" />
</Window.Resources>

Die RessourcenauflistungDataView dient dann als Bindungsquelle für Elemente in der App, z. B. die ListBox.

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" 
         ItemsSource="{Binding Source={StaticResource listingDataView}}" />

Um eine andere Ansicht für dieselbe Sammlung zu erstellen, können Sie eine andere CollectionViewSource Instanz erstellen und ihm einen anderen x:Key Namen geben.

In der folgenden Tabelle wird gezeigt, welche Ansichtsdaten-Typen als Standardansicht der Sammlung oder durch CollectionViewSource basierend auf dem Ausgangssammlungstyp erstellt werden.

Quellsammlungstyp Sammlungsansichtstyp Hinweise
IEnumerable Ein interner Typ basierend auf CollectionView Elemente können nicht gruppiert werden.
IList ListCollectionView Schnellste.
IBindingList BindingListCollectionView

Verwenden einer Standardansicht

Das Angeben einer Sammlungsansicht als Bindungsquelle ist eine Möglichkeit zum Erstellen und Verwenden einer Sammlungsansicht. WPF erstellt auch eine Standardauflistungsansicht für jede Sammlung, die als Bindungsquelle verwendet wird. Wenn Sie eine direkte Bindung an eine Auflistung herstellen, bindet WPF an die Standardansicht. Diese Standardansicht wird von allen Bindungen an derselben Auflistung gemeinsam verwendet, sodass eine Änderung an einer Standardansicht durch ein gebundenes Steuerelement oder Code (z. B. Sortieren oder Ändern des aktuellen Elementzeigers, später erläutert) in allen anderen Bindungen an dieselbe Auflistung wiedergegeben wird.

Zum Abrufen der Standardansicht verwenden Sie die GetDefaultView Methode. Ein Beispiel finden Sie unter Abrufen der Standardansicht einer Datensammlung (.NET Framework).For an example, see Get the default view of a data collection (.NET Framework).

Sammlungsansichten mit ADO.NET DataTables

Um die Leistung zu verbessern, delegieren Sammlungsansichten für ADO.NET DataTable- oder DataView-Objekte die Sortierung und Filterung an DataView, wodurch die Sortierung und Filterung über alle Sammlungsansichten der Datenquelle verteilt werden. Um jede Sammlungsansicht unabhängig zu sortieren und zu filtern, initialisieren Sie jede Auflistungsansicht mit ihrem eigenen DataView Objekt.

Sortieren

Wie bereits erwähnt, können Ansichten eine Sortierreihenfolge auf eine Sammlung anwenden. Da sie in der zugrunde liegenden Sammlung vorhanden ist, verfügen Ihre Daten möglicherweise über eine relevante, inhärente Reihenfolge. Mit der Ansicht über die Sammlung können Sie eine Bestellung auferlegen oder die Standardreihenfolge basierend auf den von Ihnen angegebenen Vergleichskriterien ändern. Da es sich um eine clientbasierte Ansicht der Daten handelt, besteht ein häufiges Szenario darin, dass der Benutzer Spalten mit tabellarischen Daten nach dem Wert sortieren möchte, dem die Spalte entspricht. Mithilfe von Ansichten kann diese benutzergesteuerte Sortierung erneut angewendet werden, ohne änderungen an der zugrunde liegenden Auflistung vorzunehmen oder sogar erneut nach dem Sammlungsinhalt abzufragn. Ein Beispiel finden Sie unter Sortieren einer GridView-Spalte, wenn auf eine Kopfzeile geklickt wird (.NET Framework).

Das folgende Beispiel zeigt die Sortierlogik des Abschnitts "Sortieren nach Kategorie und Datum" CheckBox der App-Benutzeroberfläche im Abschnitt "Datenbindung ".

private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e)
{
    // Sort the items first by Category and then by StartDate
    listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
    listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending));
}
Private Sub AddSortCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    ' Sort the items first by Category And then by StartDate
    listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
    listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub

Filterung

Ansichten können auch einen Filter auf eine Auflistung anwenden, sodass die Ansicht nur eine bestimmte Teilmenge der vollständigen Auflistung anzeigt. Möglicherweise filtern Sie nach einer Bedingung in den Daten. Wie in dem Abschnitt "Was ist Datenbindung" der App durchgeführt wird, enthält die Funktion "Nur Schnäppchen anzeigen" CheckBox eine Logik zum Filtern von Artikel, die 25 $ oder mehr kosten. Der folgende Code wird ausgeführt, um ShowOnlyBargainsFilter als Filter Ereignishandler festzulegen, wenn dies CheckBox ausgewählt ist.

private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e)
{
    if (((CheckBox)sender).IsChecked == true)
        listingDataView.Filter += ListingDataView_Filter;
    else
        listingDataView.Filter -= ListingDataView_Filter;
}
Private Sub AddFilteringCheckBox_Checked(sender As Object, e As RoutedEventArgs)
    Dim checkBox = DirectCast(sender, CheckBox)

    If checkBox.IsChecked = True Then
        AddHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    Else
        RemoveHandler listingDataView.Filter, AddressOf ListingDataView_Filter
    End If
End Sub

Der ShowOnlyBargainsFilter-Ereignishandler hat die folgende Implementierung.

private void ListingDataView_Filter(object sender, FilterEventArgs e)
{
    // Start with everything excluded
    e.Accepted = false;

    // Only inlcude items with a price less than 25
    if (e.Item is AuctionItem product && product.CurrentPrice < 25)
        e.Accepted = true;
}
Private Sub ListingDataView_Filter(sender As Object, e As FilterEventArgs)

    ' Start with everything excluded
    e.Accepted = False

    Dim product As AuctionItem = TryCast(e.Item, AuctionItem)

    If product IsNot Nothing Then

        ' Only include products with prices lower than 25
        If product.CurrentPrice < 25 Then e.Accepted = True

    End If

End Sub

Wenn Sie eine der CollectionView Klassen direkt verwenden, statt CollectionViewSource, sollten Sie die Filter Eigenschaft verwenden, um einen Rückruf anzugeben. Ein Beispiel finden Sie unter Filtern von Daten in einer Ansicht (.NET Framework).For an example, see Filter Data in a View (.NET Framework).

Gruppierung

Mit Ausnahme der internen Klasse, die eine IEnumerable Auflistung anzeigt, unterstützen alle Sammlungsansichten gruppieren, wodurch der Benutzer die Sammlung in der Sammlungsansicht in logische Gruppen partitionieren kann. Die Gruppen können explizit sein, wobei der Benutzer eine Liste von Gruppen oder implizit bereitstellt, wobei die Gruppen je nach Daten dynamisch generiert werden.

Das folgende Beispiel zeigt die Logik der "Gruppieren nach Kategorie"-Funktion CheckBox.

// This groups the items in the view by the property "Category"
var groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
listingDataView.GroupDescriptions.Add(groupDescription);
' This groups the items in the view by the property "Category"
Dim groupDescription = New PropertyGroupDescription()
groupDescription.PropertyName = "Category"
listingDataView.GroupDescriptions.Add(groupDescription)

Ein weiteres Gruppierungsbeispiel finden Sie unter "Group Items in a ListView That Implements a GridView (.NET Framework)".

Aktuelle Elementzeiger

Ansichten unterstützen auch das Konzept eines aktuellen Elements. Sie können durch die Objekte in einer Sammlungsansicht navigieren. Während Sie navigieren, verschieben Sie einen Elementzeiger, mit dem Sie das Objekt abrufen können, das an dieser bestimmten Position in der Auflistung vorhanden ist. Ein Beispiel finden Sie unter Navigieren durch die Objekte in einer Data CollectionView (.NET Framework).

Da WPF nur mithilfe einer Ansicht (einer von Ihnen angegebenen Ansicht oder der Standardansicht) an eine Auflistung gebunden wird, verfügen alle Bindungen an Sammlungen über einen aktuellen Elementzeiger. Der Schrägstrich ("/") im Path-Wert kennzeichnet beim Binden an eine Ansicht das aktuelle Element der Ansicht. Im folgenden Beispiel ist der Datenkontext eine Sammlungsansicht. Die erste Zeile wird an die Sammlung gebunden. Die zweite Zeile wird an das aktuelle Element in der Auflistung gebunden. Die dritte Zeile wird an die Description Eigenschaft des aktuellen Elements in der Auflistung gebunden.

<Button Content="{Binding }" />
<Button Content="{Binding Path=/}" />
<Button Content="{Binding Path=/Description}" />

Die Schrägstrich- und Eigenschaftensyntax kann auch gestapelt werden, um eine Hierarchie von Auflistungen zu durchlaufen. Im folgenden Beispiel wird an das aktuelle Element einer Auflistung mit dem Namen Officesgebunden, bei dem es sich um eine Eigenschaft des aktuellen Elements der Quellauflistung handelt.

<Button Content="{Binding /Offices/}" />

Der aktuelle Elementzeiger kann von jeder Sortierung oder Filterung betroffen sein, die auf die Auflistung angewendet wird. Die Sortierung behält den aktuellen Elementzeiger für das letzte ausgewählte Element bei, aber die Sammlungsansicht wird jetzt um das Element umstrukturiert. (Möglicherweise befand sich das ausgewählte Element am Anfang der Liste, aber jetzt befindet sich das ausgewählte Element möglicherweise in der Mitte.) Die Filterung behält das ausgewählte Element bei, wenn diese Auswahl nach der Filterung in der Ansicht bleibt. Andernfalls wird der aktuelle Elementzeiger auf das erste Element der gefilterten Auflistungsansicht festgelegt.

Master-Detail-Bindungsszenario

Das Konzept eines aktuellen Elements ist nicht nur für die Navigation innerhalb einer Sammlung von Elementen, sondern auch für das Master-Detail-Bindungsszenario nützlich. Berücksichtigen Sie die App-UI im Abschnitt "Was ist Datenbindung " erneut. In dieser App bestimmt die Auswahl innerhalb der ListBox Datei den inhalt, der in der ContentControlApp angezeigt wird. Anders ausgedrückt, wenn ein ListBox-Element ausgewählt wird, zeigt die ContentControl die Details des ausgewählten Elements an.

Sie können das Master-Detail-Szenario einfach implementieren, indem Sie zwei oder mehr Steuerelemente an dieselbe Ansicht gebunden haben. Das folgende Beispiel aus der zeigt das Markup der ListBox und der ContentControl auf der App-Benutzeroberfläche im Abschnitt "Was ist Datenbindung".

<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8" 
         ItemsSource="{Binding Source={StaticResource listingDataView}}" />
<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3"
                Content="{Binding Source={StaticResource listingDataView}}"
                ContentTemplate="{StaticResource detailsProductListingTemplate}" 
                Margin="9,0,0,0"/>

Beachten Sie, dass beide Steuerelemente an dieselbe Quelle gebunden sind, die statische ListingDataView-Ressource (siehe Definition dieser Ressource im Abschnitt zum Erstellen eines Ansichtsabschnitts). Diese Bindung funktioniert, weil ein Objekt (in diesem Fall das ContentControl) an eine Auflistungsansicht gebunden ist und dadurch automatisch an das CurrentItem der Ansicht gebunden wird. Die CollectionViewSource Objekte synchronisieren automatisch Währung und Auswahl. Wenn Ihr Listensteuerelement nicht wie in diesem Beispiel an ein CollectionViewSource Objekt gebunden ist, müssen Sie dessen IsSynchronizedWithCurrentItem Eigenschaft auf true festlegen, damit dies funktioniert.

Weitere Beispiele finden Sie unter Mit einer Sammlung binden und Informationen basierend auf der Auswahl anzeigen (.NET Framework) und Das Master-Detail-Muster mit hierarchischen Daten verwenden (.NET Framework).

Möglicherweise haben Sie bemerkt, dass im obigen Beispiel eine Vorlage verwendet wird. Tatsächlich würden die Daten nicht so angezeigt werden, wie wir es wünschen, ohne dass Vorlagen verwendet werden (die Vorlage, die explizit von ContentControl und die, die implizit von ListBox verwendet wird). Wir wenden uns nun an die Daten templating im nächsten Abschnitt.

Datenvorlagen

Ohne die Verwendung von Datenvorlagen würde die Benutzeroberfläche der App im Abschnitt "Datenbindung " wie folgt aussehen:

Datenbindungsdemo ohne Datenvorlagen

Wie im Beispiel im vorherigen Abschnitt gezeigt, sind sowohl das ListBox-Steuerelement als auch das ContentControl an das gesamte Auflistungsobjekt (oder genauer gesagt, die Ansicht über das Auflistungsobjekt) der AuctionItems gebunden. Ohne bestimmte Anweisungen zum Anzeigen der Datensammlung zeigt die ListBox Zeichenfolgendarstellung jedes Objekts in der zugrunde liegenden Auflistung und die ContentControl Zeichenfolgendarstellung des Objekts an, an das sie gebunden ist.

Um dieses Problem zu lösen, definiert die App DataTemplates. Wie im Beispiel im vorherigen Abschnitt gezeigt, verwendet der ContentControl explizit die Datenvorlage "detailsProductListingTemplate" . Das ListBox Steuerelement verwendet implizit die folgende Datenvorlage, wenn die AuctionItem-Objekte in der Auflistung angezeigt werden.

<DataTemplate DataType="{x:Type src:AuctionItem}">
    <Border BorderThickness="1" BorderBrush="Gray"
            Padding="7" Name="border" Margin="3" Width="500">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="86"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
                     Fill="Yellow" Stroke="Black" StrokeThickness="1"
                     StrokeLineJoin="Round" Width="20" Height="20"
                     Stretch="Fill"
                     Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
                     Visibility="Hidden" Name="star"/>

            <TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
                       Name="descriptionTitle"
                       Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
            
            <TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2"
                       Text="{Binding Path=Description}"
                       Style="{StaticResource textStyleTextBlock}"/>

            <TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
                       Name="currentPriceTitle"
                       Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
            
            <StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
                <TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
                <TextBlock Name="CurrentPriceDTDataType"
                           Text="{Binding Path=CurrentPrice}" 
                           Style="{StaticResource textStyleTextBlock}"/>
            </StackPanel>
        </Grid>
    </Border>
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Color</src:SpecialFeatures>
            </DataTrigger.Value>
            <DataTrigger.Setters>
                <Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
                <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
                <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
                <Setter Property="BorderThickness" Value="3" TargetName="border" />
                <Setter Property="Padding" Value="5" TargetName="border" />
            </DataTrigger.Setters>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=SpecialFeatures}">
            <DataTrigger.Value>
                <src:SpecialFeatures>Highlight</src:SpecialFeatures>
            </DataTrigger.Value>
            <Setter Property="BorderBrush" Value="Orange" TargetName="border" />
            <Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
            <Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
            <Setter Property="Visibility" Value="Visible" TargetName="star" />
            <Setter Property="BorderThickness" Value="3" TargetName="border" />
            <Setter Property="Padding" Value="5" TargetName="border" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

Mit der Verwendung dieser beiden DataTemplates ist die resultierende Benutzeroberfläche der im Abschnitt "Was ist Datenbindung" dargestellt. Wie Sie aus diesem Screenshot sehen können, können Sie zusätzlich dazu, dass Sie Daten in Ihren Steuerelementen platzieren können, mit DataTemplates überzeugende visuelle Elemente für Ihre Daten definieren. So werden z. B. DataTriggers oben verwendet, sodass Auktionselemente mit einem SpecialFeatures-Wert von HighLight mit einem orangefarbenen Rahmen und einem Stern angezeigt werden.

Weitere Informationen zu Datenvorlagen finden Sie in der Übersicht über datenvorlagen (.NET Framework).

Datenvalidierung

Die meisten Apps, die Benutzereingaben übernehmen, müssen über eine Validierungslogik verfügen, um sicherzustellen, dass der Benutzer die erwarteten Informationen eingegeben hat. Die Überprüfungen können auf Typ, Bereich, Format oder anderen appspezifischen Anforderungen basieren. In diesem Abschnitt wird erläutert, wie die Datenüberprüfung in WPF funktioniert.

Zuordnen von Validierungsregeln zu einer Bindung

Mit dem WPF-Datenbindungsmodell können Sie ValidationRules mit Ihrem Binding Objekt verbinden. Im folgenden Beispiel wird eine TextBox an einer Eigenschaft mit dem Namen StartPrice gebunden und ein ExceptionValidationRule Objekt der Binding.ValidationRules Eigenschaft hinzugefügt.

<TextBox Name="StartPriceEntryForm" Grid.Row="2"
         Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
    <TextBox.Text>
        <Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <ExceptionValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Ein ValidationRule Objekt überprüft, ob der Wert einer Eigenschaft gültig ist. WPF verfügt über zwei Typen von integrierten ValidationRule Objekten:

Sie können auch eine eigene Gültigkeitsprüfungsregel erstellen, indem Sie von der ValidationRule Klasse abgeleitet und die Validate Methode implementieren. Das folgende Beispiel zeigt die Regel, die vom Add Product Listing "Start Date" aus dem Abschnitt Was ist Datenbindung verwendet wird.

public class FutureDateRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        // Test if date is valid
        if (DateTime.TryParse(value.ToString(), out DateTime date))
        {
            // Date is not in the future, fail
            if (DateTime.Now > date)
                return new ValidationResult(false, "Please enter a date in the future.");
        }
        else
        {
            // Date is not a valid date, fail
            return new ValidationResult(false, "Value is not a valid date.");
        }

        // Date is valid and in the future, pass
        return ValidationResult.ValidResult;
    }
}
Public Class FutureDateRule
    Inherits ValidationRule

    Public Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As ValidationResult

        Dim inputDate As Date

        ' Test if date is valid
        If Date.TryParse(value.ToString, inputDate) Then

            ' Date is not in the future, fail
            If Date.Now > inputDate Then
                Return New ValidationResult(False, "Please enter a date in the future.")
            End If

        Else
            ' // Date Is Not a valid date, fail
            Return New ValidationResult(False, "Value is not a valid date.")
        End If

        ' Date is valid and in the future, pass
        Return ValidationResult.ValidResult

    End Function

End Class

Das StartDateEntryFormTextBox verwendet dieses FutureDateRule,wie im folgenden Beispiel gezeigt.

<TextBox Name="StartDateEntryForm" Grid.Row="3"
         Validation.ErrorTemplate="{StaticResource validationTemplate}" 
         Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
    <TextBox.Text>
        <Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged" 
                 Converter="{StaticResource dateConverter}" >
            <Binding.ValidationRules>
                <src:FutureDateRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Da der UpdateSourceTrigger Wert lautet PropertyChanged, aktualisiert das Bindungsmodul den Quellwert für jeden Tastenanschlag, was bedeutet, dass auch jede Regel in der ValidationRules Auflistung auf jedem Tastenanschlag überprüft wird. Dies wird im Abschnitt "Validierungsprozess" weiter erläutert.

Bereitstellen von visuellem Feedback

Wenn der Benutzer einen ungültigen Wert eingibt, sollten Sie möglicherweise Feedback zu dem Fehler auf der App-Benutzeroberfläche geben. Eine Möglichkeit zum Bereitstellen eines solchen Feedbacks besteht darin, die Validation.ErrorTemplate angefügte Eigenschaft auf eine benutzerdefinierte ControlTemplateEigenschaft festzulegen. Wie im vorherigen Unterabschnitt gezeigt, verwendet " StartDateEntryFormTextBox " eine ErrorTemplate sogenannte validationTemplate. Das folgende Beispiel zeigt die Definition von validationTemplate.

<ControlTemplate x:Key="validationTemplate">
    <DockPanel>
        <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
        <AdornedElementPlaceholder/>
    </DockPanel>
</ControlTemplate>

Das AdornedElementPlaceholder Element gibt an, wo das zu schmückende Steuerelement platziert werden soll.

Darüber hinaus können Sie auch eine ToolTip zum Anzeigen der Fehlermeldung verwenden. Sowohl " StartDateEntryForm " als auch " StartPriceEntryFormTextBox" verwenden das Format "textStyleTextBox", das eine ToolTip Fehlermeldung anzeigt. Das folgende Beispiel zeigt die Definition von textStyleTextBox. Die angefügte Eigenschaft Validation.HasError ist true , wenn mindestens eine der Bindungen für die Eigenschaften des gebundenen Elements fehlerhaft ist.

<Style x:Key="textStyleTextBox" TargetType="TextBox">
    <Setter Property="Foreground" Value="#333333" />
    <Setter Property="MaxLength" Value="40" />
    <Setter Property="Width" Value="392" />
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip" 
                    Value="{Binding (Validation.Errors).CurrentItem.ErrorContent, RelativeSource={RelativeSource Self}}" />
        </Trigger>
    </Style.Triggers>
</Style>

Mit der benutzerdefinierten ErrorTemplate und der ToolTip sieht das StartDateEntryForm-FormularTextBox wie folgt aus, wenn ein Validierungsfehler auftritt.

Datenbindungsüberprüfungsfehler für Datum

Wenn Ihre Binding Gültigkeitsprüfungsregeln zugeordnet sind, Sie jedoch kein ErrorTemplate an das gebundene Steuerelement angeben, wird ein Standard ErrorTemplate verwendet, um Benutzer zu benachrichtigen, wenn ein Validierungsfehler auftritt. Der Standardwert ErrorTemplate ist eine Steuerelementvorlage, die einen roten Rahmen in der Verziererebene definiert. Die Benutzeroberfläche des StartPriceEntryFormTextBox sieht bei Standard ErrorTemplate und ToolTip wie folgt aus, wenn ein Validierungsfehler auftritt.

Fehler bei der Datenbindungsüberprüfung für den Preis

Ein Beispiel für die Bereitstellung von Logik zum Überprüfen aller Steuerelemente in einem Dialogfeld finden Sie im Abschnitt "Benutzerdefinierte Dialogfelder" in der Übersicht über Dialogfelder.

Validierungsprozess

Die Überprüfung erfolgt in der Regel, wenn der Wert eines Ziels an die Bindungsquelleigenschaft übertragen wird. Diese Übertragung erfolgt auf TwoWay und OneWayToSource Bindungen. Was eine Quellaktualisierung bewirkt, hängt erneut vom Wert der UpdateSourceTrigger Eigenschaft ab, wie im Abschnitt "What triggers source updates" beschrieben.

Die folgenden Elemente beschreiben den Überprüfungsprozess . Wenn während dieses Prozesses ein Überprüfungsfehler oder ein anderer Fehlertyp auftritt, wird der Prozess angehalten:

  1. Die Bindungs-Engine überprüft, ob benutzerdefinierte ValidationRule-Objekte definiert sind, deren ValidationStep auf RawProposedValue für diesen Binding festgelegt ist. Sollte dies der Fall sein, ruft sie die Validate-Methode bei jedem ValidationRule auf, bis einer von ihnen auf einen Fehler stößt oder bis alle übergeben werden.

  2. Das Bindungsmodul ruft dann den Konverter auf, falls vorhanden.

  3. Wenn der Konverter erfolgreich ist, überprüft die Bindungsmaschine, ob benutzerdefinierte ValidationRule Objekte definiert sind, deren ValidationStep auf Binding festgelegt ConvertedProposedValue ist. In diesem Fall ruft sie die Validate Methode für jedes ValidationRule Objekt auf, bei dem ValidationStep auf ConvertedProposedValue eingestellt wird, bis eines davon auf einen Fehler stößt oder bis alle erfolgreich sind.

  4. Die Bindungsmaschine legt die Quelleigenschaft fest.

  5. Das Bindungsmodul überprüft, ob benutzerdefinierte ValidationRule Objekte definiert sind, deren ValidationStep auf UpdatedValue für Binding festgelegt ist. In diesem Fall ruft es die Validate Methode für jedes ValidationRule auf, das auf ValidationStep gesetzt ist UpdatedValue, bis eines von ihnen auf einen Fehler stößt oder bis alle erfolgreich sind. Wenn eine DataErrorValidationRule zu einer Bindung zugeordnet ist und ihr ValidationStep auf die Standardeinstellung UpdatedValue festgelegt ist, wird DataErrorValidationRule an diesem Punkt überprüft. An diesem Punkt wird jede Bindung überprüft, bei der ValidatesOnDataErrors auf true gesetzt ist.

  6. Das Bindungsmodul überprüft, ob benutzerdefinierte ValidationRule Objekte definiert sind, deren ValidationStep auf CommittedValue für diesen Binding festgelegt ist. In diesem Fall ruft es die Validate-Methode für jedes ValidationRule auf, das auf CommittedValue für ValidationStep festgelegt wurde, bis eines von ihnen auf einen Fehler stößt oder alle erfolgreich durchlaufen wurden.

Wenn ein Objekt ValidationRule während dieses Prozesses nicht übergeben wird, erstellt das Bindungsmodul ein ValidationError Objekt und fügt es der Validation.Errors Auflistung des gebundenen Elements hinzu. Bevor das Bindungsmodul die ValidationRule Objekte in einem bestimmten Schritt ausführt, entfernt es alle ValidationError Objekte, die während dieses Schritts der Validation.Errors angefügten Eigenschaft des gebundenen Elements hinzugefügt wurden. Zum Beispiel entfernt das Bindungsmodul, wenn ein ValidationRule mit eingestelltem ValidationStepUpdatedValue fehlgeschlagen ist, beim nächsten Auftreten des Überprüfungsprozesses dieses ValidationError, unmittelbar bevor es ein ValidationRule aufruft, das ValidationStep auf UpdatedValue gesetzt hat.

Wenn Validation.Errors nicht leer ist, wird die Validation.HasError angefügte Eigenschaft des Elements auf truefestgelegt. Wenn die NotifyOnValidationError Eigenschaft des Binding Elements auf true festgelegt ist, dann löst die Bindungs-Engine das Validation.Error angefügte Ereignis für das Element aus.

Beachten Sie außerdem, dass eine gültige Wertübertragung in beide Richtungen (Ziel für Quelle oder Quelle zum Ziel) die Validation.Errors angefügte Eigenschaft löscht.

Wenn die Bindung entweder über eine ExceptionValidationRule-Eigenschaft verfügt oder die ValidatesOnExceptions-Eigenschaft auf true festgelegt wurde und eine Ausnahme ausgelöst wird, wenn die Bindungsengine die Quelle festlegt, überprüft die Bindungsengine, ob ein UpdateSourceExceptionFilter-Objekt vorhanden ist. Sie können den UpdateSourceExceptionFilter Rückruf verwenden, um einen benutzerdefinierten Handler für die Behandlung von Ausnahmen bereitzustellen. Wenn keine UpdateSourceExceptionFilter auf der Binding Bindungs-Engine angegeben ist, erstellt die Bindungs-Engine ein ValidationError Objekt mit der Ausnahme und fügt es der Validation.Errors Sammlung des gebundenen Elements hinzu.

Debugmechanismus

Sie können die angefügte Eigenschaft PresentationTraceSources.TraceLevel für ein bindungsbezogenes Objekt festlegen, um Informationen zum Status einer bestimmten Bindung zu erhalten.

Siehe auch