Delen via


Overzicht van gegevensbinding (WPF .NET)

Gegevensbinding in Windows Presentation Foundation (WPF) biedt een eenvoudige en consistente manier voor apps om gegevens te presenteren en ermee te communiceren. Elementen kunnen worden gebonden aan gegevens uit verschillende soorten gegevensbronnen in de vorm van .NET-objecten en XML. Alle ContentControl zoals Button en alle ItemsControl, zoals ListBox en ListView, hebben ingebouwde functionaliteit om flexibele stijl te bieden voor afzonderlijke gegevensitems of verzamelingen gegevensitems. Boven op de gegevens kunnen sorteer-, filter- en groepsweergaven worden gegenereerd.

De gegevensbinding in WPF heeft verschillende voordelen ten opzichte van traditionele modellen, waaronder inherente ondersteuning voor gegevensbinding door een breed scala aan eigenschappen, flexibele UI-weergave van gegevens en schone scheiding van bedrijfslogica van de gebruikersinterface.

In dit artikel worden eerst concepten besproken die fundamenteel zijn voor WPF-gegevensbinding en vervolgens het gebruik van de Binding-klasse en andere functies van gegevensbinding.

Wat is gegevensbinding?

Gegevensbinding is het proces waarmee een verbinding tot stand wordt gebracht tussen de gebruikersinterface van de app en de gegevens die worden weergegeven. Als de binding de juiste instellingen heeft en de gegevens de juiste meldingen geven, worden de elementen die zijn gebonden aan de gegevens automatisch aangepast wanneer de gegevens de waarde ervan wijzigen. Gegevensbinding kan ook betekenen dat als een externe weergave van de gegevens in een element verandert, de onderliggende gegevens automatisch kunnen worden bijgewerkt om de wijziging weer te geven. Als de gebruiker bijvoorbeeld de waarde in een TextBox element bewerkt, wordt de onderliggende gegevenswaarde automatisch bijgewerkt om deze wijziging weer te geven.

Een typisch gebruik van gegevensbinding is het plaatsen van server- of lokale configuratiegegevens in formulieren of andere besturingselementen voor de gebruikersinterface. In WPF wordt dit concept uitgebreid met het binden van een breed scala aan eigenschappen aan verschillende soorten gegevensbronnen. In WPF kunnen afhankelijkheidseigenschappen van elementen worden gebonden aan .NET-objecten (inclusief ADO.NET objecten of objecten die zijn gekoppeld aan webservices en webeigenschappen) en XML-gegevens.

Basisconcepten voor gegevensbinding

Ongeacht het element dat u bindt en de aard van uw gegevensbron, volgt elke binding altijd het model dat wordt geïllustreerd door de volgende afbeelding.

diagram met het basismodel voor gegevensbinding.

Zoals in de afbeelding wordt weergegeven, is gegevensbinding in feite de brug tussen uw bindingsdoel en uw bindingsbron. In de afbeelding ziet u de volgende fundamentele concepten voor WPF-gegevensbinding:

  • Normaal gesproken heeft elke binding vier onderdelen:

    • Een bindingsdoelobject.
    • Een beoogde eigenschap.
    • Een bron die bindt.
    • Een pad naar de waarde in de bindingsbron die moet worden gebruikt.

    Als u bijvoorbeeld de inhoud van een TextBox aan de eigenschap Employee.Name hebt gebonden, stelt u de binding in zoals in de volgende tabel:

    Instelling Waarde
    Doel TextBox
    Doeleigenschap Text
    Bronobject Employee
    Pad naar bronobjectwaarde Name
  • De doeleigenschap moet een afhankelijkheidseigenschap zijn.

    De meeste UIElement eigenschappen zijn afhankelijkheidseigenschappen en de meeste afhankelijkheidseigenschappen, met uitzondering van alleen-lezen eigenschappen, ondersteunen standaard gegevensbinding. Alleen typen die zijn afgeleid van DependencyObject kunnen afhankelijkheidseigenschappen definiëren. Alle UIElement typen zijn afgeleid van DependencyObject.

  • Bindingsbronnen zijn niet beperkt tot aangepaste .NET-objecten.

    Hoewel deze niet wordt weergegeven in de afbeelding, moet u er wel op merken dat het bindingsbronobject niet beperkt is tot een aangepast .NET-object. WPF-gegevensbinding ondersteunt gegevens in de vorm van .NET-objecten, XML en zelfs XAML-elementobjecten. Als u enkele voorbeelden wilt opgeven, kan uw bindingsbron een UIElementzijn, een lijstobject, een ADO.NET- of Web Services-object of een XmlNode die uw XML-gegevens bevat. Zie Overzicht van bindingsbronnenvoor meer informatie.

Het is belangrijk om te onthouden dat wanneer u een binding maakt, u een bindingsdoel aan een bindingsbron verbindt. Als u bijvoorbeeld bepaalde onderliggende XML-gegevens weergeeft in een ListBox met behulp van gegevensbinding, moet u uw ListBox koppelen aan de XML-gegevens.

Als u een binding tot stand wilt brengen, gebruikt u het Binding-object. In de rest van dit artikel worden veel concepten besproken die zijn gekoppeld aan en enkele eigenschappen en het gebruik van het Binding-object.

Gegevenscontext

Wanneer gegevensbinding wordt gedeclareerd op XAML-elementen, lossen ze de gegevensbinding op door hun directe DataContext-eigenschap te bekijken. De gegevenscontext is doorgaans het bindingsbronobject voor het evalueren van het bindingsbronwaarde pad. U kunt dit gedrag in de binding overschrijven en een specifieke waarde voor het bindingsbron-object instellen. Als de eigenschap DataContext voor het object dat als host voor de binding fungeert niet is ingesteld, wordt de eigenschap DataContext van het bovenliggende element gecontroleerd, enzovoort tot de wortel van de XAML-objectboom. Kortom, de gegevenscontext die wordt gebruikt om binding op te lossen, wordt overgenomen van het bovenliggende item, tenzij deze expliciet is ingesteld voor het object.

Bindingen kunnen worden geconfigureerd om op te lossen met een specifiek object, in tegenstelling tot het gebruik van de gegevenscontext voor bindingsresolutie. Het rechtstreeks opgeven van een bronobject wordt gebruikt wanneer u bijvoorbeeld de voorgrondkleur van een object verbindt met de achtergrondkleur van een ander object. Een gegevenscontext is niet nodig omdat de binding tussen die twee objecten wordt opgelost. Bindingen die niet zijn gebonden aan specifieke bronobjecten, maken omgekeerd gebruik van gegevenscontextomzetting.

Wanneer de eigenschap DataContext wordt gewijzigd, worden alle bindingen die kunnen worden beïnvloed door de gegevenscontext opnieuw geëvalueerd.

Richting van de gegevensstroom

Zoals aangegeven met de pijl in de vorige afbeelding, kan de gegevensstroom van een binding van het bindingsdoel naar de bindingsbron gaan (de bronwaarde verandert bijvoorbeeld wanneer een gebruiker de waarde van een TextBox) bewerkt en/of van de bindingsbron naar het bindingsdoel (bijvoorbeeld uw TextBox inhoud wordt bijgewerkt met wijzigingen in de bindingsbron) als de bindingsbron de juiste meldingen geeft.

Mogelijk wilt u dat uw app gebruikers in staat stelt om de gegevens te wijzigen en deze weer door te geven aan het bronobject. Of u wilt gebruikers mogelijk niet in staat stellen om de brongegevens bij te werken. U kunt de gegevensstroom beheren door het Binding.Modein te stellen.

In deze afbeelding ziet u de verschillende typen gegevensstromen:

gegevensbindingsgegevensstroom

  • OneWay binding zorgt ervoor dat wijzigingen in de broneigenschap de doeleigenschap automatisch bijwerken, maar wijzigingen in de doeleigenschap worden niet teruggegeven aan de broneigenschap. Dit type koppeling is geschikt als het besturingselement impliciet alleen lezen is. U kunt bijvoorbeeld binden aan een bron, zoals een aandelen ticker, of misschien heeft uw doeleigenschap geen besturingsinterface voor het aanbrengen van wijzigingen, zoals een gegevensgebonden achtergrondkleur van een tabel. Als u de wijzigingen van de doeleigenschap niet hoeft te controleren, voorkomt u de overhead van de TwoWay bindingsmodus met behulp van de OneWay bindingsmodus.

  • TwoWay-binding zorgt ervoor dat wijzigingen in de broneigenschap of de doeleigenschap de andere automatisch bijwerken. Dit type binding is geschikt voor bewerkbare formulieren of andere volledig interactieve UI-scenario's. De meeste eigenschappen worden standaard ingesteld op OneWay-binding, maar sommige afhankelijkheidseigenschappen (meestal eigenschappen van door de gebruiker bewerkbare besturingselementen, zoals het selectievakje TextBox.Text en CheckBox.IsChecked) worden standaard ingesteld op TwoWay-binding.

    Een programmatische manier om te bepalen of een afhankelijkheidseigenschap standaard eenrichtingsbinding of tweerichtingsbinding heeft, is door de metagegevens van een eigenschap op te halen met DependencyProperty.GetMetadata. Het retourtype van deze methode is PropertyMetadata, die geen metagegevens over binding bevat. Als dit type echter kan worden omgezet in de afgeleide FrameworkPropertyMetadata, kan de Booleaanse waarde van de eigenschap FrameworkPropertyMetadata.BindsTwoWayByDefault worden gecontroleerd. In het volgende codevoorbeeld ziet u hoe u de metagegevens voor de eigenschap TextBox.Text ophaalt:

    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 is het omgekeerde van OneWay binding; de broneigenschap wordt bijgewerkt wanneer de doeleigenschap wordt gewijzigd. Een voorbeeldscenario is als u de bronwaarde alleen opnieuw hoeft te evalueeren vanuit de gebruikersinterface.

  • Niet geïllustreerd in de afbeelding is OneTime binding, waardoor de broneigenschap de doeleigenschap initialiseert, maar geen latere wijzigingen doorgeeft. Als de gegevenscontext verandert of het object in de gegevenscontext verandert, wordt de wijziging niet weergegeven in de doeleigenschap. Dit type binding is geschikt als een momentopname van de huidige status geschikt is of de gegevens echt statisch zijn. Dit type binding is ook handig als u de doeleigenschap wilt initialiseren met een bepaalde waarde van een broneigenschap en de gegevenscontext niet van tevoren bekend is. Deze modus is in wezen een eenvoudigere vorm van OneWay binding die betere prestaties biedt in gevallen waarin de bronwaarde niet verandert.

Als u bronwijzigingen wilt detecteren (van toepassing op OneWay en TwoWay bindingen), moet de bron een geschikt mechanisme voor het wijzigen van eigenschappen implementeren, zoals INotifyPropertyChanged. Zie Instructies: Melding voor het wijzigen van eigenschappen (.NET Framework) implementeren voor een voorbeeld van een INotifyPropertyChanged-implementatie.

De eigenschap Binding.Mode biedt meer informatie over bindingsmodi en een voorbeeld van het opgeven van de richting van een binding.

Wat veroorzaakt bronupdates?

Bindingen die zijn TwoWay of OneWayToSource luisteren naar wijzigingen in de doeleigenschap en deze doorgeven aan de bron, ook wel bekend als het bijwerken van de bron. U kunt bijvoorbeeld de tekst van een tekstvak bewerken om de onderliggende bronwaarde te wijzigen.

Is de bronwaarde echter bijgewerkt terwijl u de tekst bewerkt of nadat u klaar bent met het bewerken van de tekst en het besturingselement de focus verliest? De eigenschap Binding.UpdateSourceTrigger bepaalt wat de update van de bron activeert. In de volgende afbeelding illustreren de stipjes van de rechter pijlen de rol van de eigenschap Binding.UpdateSourceTrigger.

Diagram met de rol van de eigenschap UpdateSourceTrigger.

Als de UpdateSourceTrigger waarde UpdateSourceTrigger.PropertyChangedis, wordt de waarde waarnaar de rechterpijl van TwoWay of de OneWayToSource-bindingen verwijst bijgewerkt zodra de doel-eigenschap verandert. Als de UpdateSourceTrigger waarde echter LostFocusis, wordt die waarde alleen bijgewerkt met de nieuwe waarde wanneer de doeleigenschap de focus verliest.

Net als bij de eigenschap Mode hebben verschillende afhankelijkheidseigenschappen verschillende standaardwaarden UpdateSourceTrigger. De standaardwaarde voor de meeste afhankelijkheidseigenschappen is PropertyChanged, waardoor de waarde van de broneigenschap direct wordt gewijzigd wanneer de doeleigenschapswaarde wordt gewijzigd. Directe wijzigingen zijn prima voor CheckBox en andere eenvoudige controles. Voor tekstvelden kan het bijwerken na elke toetsaanslag echter de prestaties verminderen en weigert de gebruiker de gebruikelijke kans om backspace te maken en typfouten op te lossen voordat de nieuwe waarde wordt doorgevoerd. De eigenschap TextBox.Text wordt bijvoorbeeld standaard ingesteld op de UpdateSourceTrigger waarde van LostFocus, waardoor de bronwaarde alleen wordt gewijzigd wanneer het besturingselement de focus verliest, niet wanneer de eigenschap TextBox.Text wordt gewijzigd. Zie de UpdateSourceTrigger eigenschappenpagina voor informatie over het vinden van de standaardwaarde van een afhankelijkheidseigenschap.

De volgende tabel bevat een voorbeeldscenario voor elke UpdateSourceTrigger waarde met behulp van de TextBox als voorbeeld.

UpdateSourceTrigger-waarde Wanneer de bronwaarde wordt bijgewerkt Voorbeeldscenario voor tekstvak
LostFocus (standaardinstelling voor TextBox.Text) Wanneer het Tekstvak-besturingselement de focus verliest. Een tekstvak dat is gekoppeld aan validatielogica (zie gegevensvalidatie hieronder).
PropertyChanged Terwijl u in de TextBoxtypt. Tekstvakbesturingselementen in een chatvenster.
Explicit Wanneer de app UpdateSourceaanroept. Besturingselementen voor tekstvakken in een bewerkbaar formulier (werkt de bronwaarden alleen bij wanneer de gebruiker op de knop Verzenden drukt).

Zie voor een voorbeeld Procedure: Bepalen wanneer de tekst van het tekstvak de bron (.NET Framework) bijwerkt.

Voorbeeld van gegevensbinding

Bekijk voor een voorbeeld van gegevensbinding de gebruikersinterface van de Data Binding Demo, waarin een lijst met veilingitems wordt weergegeven.

Schermopname gegevensbindingsvoorbeeld

De app demonstreert de volgende functies van gegevensbinding:

  • De inhoud van de ListBox is gebonden aan een verzameling AuctionItem objecten. Een AuctionItem--object heeft eigenschappen zoals Description, StartPrice, StartDate, Categoryen SpecialFeatures.

  • De gegevens (AuctionItem objecten) die in de ListBox worden weergegeven, worden zodanig gesjabloond dat de beschrijving en de huidige prijs voor elk item worden weergegeven. De sjabloon wordt gemaakt met behulp van een DataTemplate. Bovendien is het uiterlijk van elk item afhankelijk van de waarde van de SpecialFeatures wanneer het AuctionItem wordt weergegeven. Als de SpecialFeatures-waarde van het AuctionItem de Coloris, heeft het item een blauwe rand. Als de waarde is Markeren, heeft het item een oranje rand en een ster. De sectie Gegevenssjablonering bevat informatie over gegevenssjablonering.

  • De gebruiker kan de gegevens groeperen, filteren of sorteren met behulp van de opgegeven CheckBoxes. In de bovenstaande afbeelding zijn de Groeperen op categorie en Sorteren op categorie en datumCheckBoxes geselecteerd. Mogelijk hebt u gemerkt dat de gegevens zijn gegroepeerd op basis van de categorie van het product en dat de categorienaam alfabetisch is. Het is moeilijk om te zien vanaf de afbeelding, maar de items worden ook gesorteerd op de begindatum binnen elke categorie. Sorteren wordt uitgevoerd met behulp van een verzamelingsweergave. In de sectie Binding met verzamelingen worden verzamelingsweergaven besproken.

  • Wanneer de gebruiker een item selecteert, worden in de ContentControl de details van het geselecteerde item weergegeven. Deze ervaring wordt het masterdetailscenariogenoemd. De Master-detail scenario sectie bevat informatie over dit type koppeling.

  • Het type van de eigenschap StartDate is DateTime, waarmee een datum wordt geretourneerd die de tijd tot de milliseconde bevat. In deze app is een aangepast conversieprogramma gebruikt, zodat een kortere datumtekenreeks wordt weergegeven. De sectie Gegevensconversie bevat informatie over conversieprogramma's.

Wanneer de gebruiker de knop Product toevoegen selecteert, wordt het volgende formulier weergegeven.

pagina Productvermelding toevoegen

De gebruiker kan de velden in het formulier bewerken, een voorbeeld van de productvermelding bekijken met behulp van de korte of gedetailleerde voorbeeldvensters en Submit selecteren om de nieuwe productvermelding toe te voegen. Alle bestaande groeperings-, filter- en sorteerinstellingen zijn van toepassing op de nieuwe vermelding. In dit specifieke geval wordt het item dat in de bovenstaande afbeelding is ingevoerd, weergegeven als het tweede item in de categorie Computer.

Niet weergegeven in deze afbeelding is de validatielogica die is opgegeven in de begindatumTextBox. Als de gebruiker een ongeldige datum invoert (ongeldige opmaak of een eerdere datum), krijgt de gebruiker een melding met een ToolTip en een rood uitroepteken naast de TextBox. In de sectie Gegevensvalidatie wordt beschreven hoe u validatielogica maakt.

Voordat u verdergaat met de verschillende functies van gegevensbinding die hierboven worden beschreven, bespreken we eerst de fundamentele concepten die essentieel zijn voor het begrijpen van WPF-gegevensbinding.

Een binding maken

Als u enkele van de concepten die in de vorige secties zijn besproken, wilt aanpassen, maakt u een binding met behulp van het Binding-object en heeft elke binding meestal vier onderdelen: een bindingsdoel, een doeleigenschap, een bindingsbron en een pad naar de bronwaarde die moet worden gebruikt. In deze sectie wordt beschreven hoe u een binding instelt.

Bindingsbronnen zijn gekoppeld aan de actieve DataContext voor het element. Elementen erven automatisch hun DataContext als ze er niet expliciet een gedefinieerd hebben.

Bekijk het volgende voorbeeld, waarin het bindingsbronobject een klasse is met de naam MyData- die is gedefinieerd in de SDKSample-naamruimte. Voor demonstratiedoeleinden heeft MyData- een tekenreekseigenschap met de naam ColorName waarvan de waarde is ingesteld op 'Rood'. In dit voorbeeld wordt dus een knop met een rode achtergrond gegenereerd.

<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>

Zie Overzicht van bindingsdeclaratiesvoor meer informatie over de syntaxis van bindingsdeclaraties en voorbeelden van het instellen van een binding in code.

Als we dit voorbeeld toepassen op ons basisdiagram, ziet de resulterende afbeelding er als volgt uit. In deze afbeelding wordt een OneWay binding beschreven omdat de eigenschap Background standaard ondersteuning biedt voor OneWay binding.

Diagram dat de eigenschap Achtergrond van gegevensbinding toont.

U vraagt zich misschien af waarom deze binding werkt, ook al is de eigenschap ColorName van het type tekenreeks terwijl de eigenschap Background van het type Brushis. Deze binding maakt gebruik van standaardtypeconversie, die wordt besproken in de sectie Gegevensconversie.

De bindingsbron opgeven

In het vorige voorbeeld wordt de bindingsbron opgegeven door de eigenschap DockPanel.DataContext in te stellen. De Button neemt vervolgens de DataContext-waarde over van de DockPanel, het bovenliggende element. Om dit nogmaals te herhalen, is het bindingbronobject een van de vier vereiste onderdelen van een binding. Dus, zonder dat het bindingsbronobject wordt opgegeven, zou de binding niets doen.

Er zijn verschillende manieren om het bindingsbronobject op te geven. Het gebruik van de eigenschap DataContext op een bovenliggend element is handig wanneer u meerdere eigenschappen aan dezelfde bron wilt koppelen. Soms is het echter beter om de bindingsbron op te geven voor afzonderlijke bindingsdeclaraties. In het vorige voorbeeld kunt u in plaats van de eigenschap DataContext de bindingsbron opgeven door de eigenschap Binding.Source rechtstreeks in te stellen op de bindingsdeclaratie van de knop, zoals in het volgende voorbeeld.

<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>

Behalve het rechtstreeks instellen van de eigenschap DataContext op een element, het overnemen van de DataContext waarde van een bovenliggende eigenschap (zoals de knop in het eerste voorbeeld) en het expliciet opgeven van de bindingsbron door de eigenschap Binding.Source op de binding in te stellen (zoals de knop in het laatste voorbeeld), kunt u ook de eigenschap Binding.ElementName of de eigenschap Binding.RelativeSource gebruiken om de bindingsbron op te geven. De eigenschap ElementName is handig wanneer u verbinding maakt met andere elementen in uw app, zoals wanneer u een schuifregelaar gebruikt om de breedte van een knop aan te passen. De eigenschap RelativeSource is handig wanneer de binding is opgegeven in een ControlTemplate of een Style. Zie Overzicht van bindingsbronnenvoor meer informatie.

Het pad naar de waarde opgeven

Als uw bindingsbron een object is, gebruikt u de eigenschap Binding.Path om de waarde op te geven die u voor de binding wilt gebruiken. Als u binding wilt maken met XML-gegevens, gebruikt u de eigenschap Binding.XPath om de waarde op te geven. In sommige gevallen kan het van toepassing zijn om de eigenschap Path te gebruiken, zelfs wanneer uw gegevens XML zijn. Als u bijvoorbeeld toegang wilt krijgen tot de eigenschap Name van een geretourneerde XmlNode (als gevolg van een XPath-query), moet u de eigenschap Path naast de eigenschap XPath gebruiken.

Zie de eigenschappen Path en XPath voor meer informatie.

Hoewel we hebben benadrukt dat de Path voor de te gebruiken waarde een van de vier benodigde onderdelen van een binding is, is in de scenario's die u aan een heel object wilt binden, de te gebruiken waarde hetzelfde als het bindingsbronobject. In die gevallen is het van toepassing om geen Pathop te geven. Bekijk het volgende voorbeeld.

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

In het bovenstaande voorbeeld wordt de lege bindingsyntaxis gebruikt: {Binding}. In dit geval erft ListBox de DataContext van een ouder DockPanel-element dat niet in dit voorbeeld wordt weergegeven. Wanneer het pad niet is opgegeven, is de standaardwaarde het verbinden met het hele object. Met andere woorden, in dit voorbeeld is het pad weggelaten omdat we de eigenschap ItemsSource koppelen aan het hele object. (Zie de paragraaf Binding aan verzamelingen voor een uitgebreidere discussie.)

Afgezien van het binden aan een verzameling, is dit scenario ook handig als u een hele object wilt binden in plaats van slechts één eigenschap van een object. Als uw bronobject bijvoorbeeld van het type Stringis, kunt u gewoon een binding met de tekenreeks zelf maken. Een ander veelvoorkomend scenario is wanneer u een element wilt binden aan een object met verschillende eigenschappen.

Mogelijk moet u aangepaste logica toepassen, zodat de gegevens zinvol zijn voor uw afhankelijke doeleigenschap. De aangepaste logica kan de vorm hebben van een aangepast conversieprogramma als er geen standaardtypeconversie bestaat. Zie gegevensconversie voor informatie over conversieprogramma's.

Binding en BindingExpression

Voordat u toegang krijgt tot andere functies en het gebruik van gegevensbinding, is het handig om de BindingExpression-klasse te introduceren. Zoals u in de vorige secties hebt gezien, is de Binding klasse de klasse op hoog niveau voor de declaratie van een binding; het biedt veel eigenschappen waarmee u de kenmerken van een binding kunt opgeven. Een gerelateerde klasse, BindingExpression, is het onderliggende object dat de verbinding tussen de bron en het doel onderhoudt. Een binding bevat alle informatie die kan worden gedeeld over verschillende bindingexpressies. Een BindingExpression is een exemplaarexpressie die niet kan worden gedeeld en alle exemplaargegevens van de Bindingbevat.

Bekijk het volgende voorbeeld, waarbij myDataObject een exemplaar van de klasse MyData is, myBinding het bronobject Binding is en MyData een gedefinieerde klasse is die een tekenreekseigenschap met de naam ColorNamebevat. In dit voorbeeld wordt de tekstinhoud van myText, een exemplaar van TextBlock, gekoppeld aan ColorName.

// 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)

U kunt dezelfde myBinding-object gebruiken om andere bindingen te maken. U kunt bijvoorbeeld het object myBinding gebruiken om de tekstinhoud van een selectievakje te binden aan ColorName. In dat scenario zullen er twee exemplaren van dat BindingExpression deelnemen aan het myBinding-object.

Een BindingExpression-object wordt geretourneerd door GetBindingExpression aan te roepen op een gegevensgebonden object. In de volgende artikelen worden enkele van de gebruiksrechten van de BindingExpression-klasse gedemonstreert:

Gegevensconversie

In de sectie Een binding maken is de knop rood omdat de eigenschap Background is gebonden aan een tekenreekseigenschap met de waarde 'Rood'. Deze tekenreekswaarde werkt omdat een typeconversieprogramma aanwezig is op het Brush type om de tekenreekswaarde te converteren naar een Brush.

Door deze informatie toe te voegen aan de figuur in de sectie Een binding maken, ziet het er als volgt uit.

Diagram met de standaardeigenschap voor gegevensbinding.

Wat gebeurt er echter als uw bindingsbronobject in plaats van een eigenschap van het type tekenreeks een eigenschap Color van het type Colorheeft? In dat geval moet u eerst de eigenschapswaarde van Color omzetten in een vorm die door de Background eigenschap wordt geaccepteerd. U moet een aangepast conversieprogramma maken door de IValueConverter-interface te implementeren, zoals in het volgende voorbeeld.

[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

Zie IValueConverter voor meer informatie.

Het aangepaste conversieprogramma wordt nu gebruikt in plaats van standaardconversie en ons diagram ziet er als volgt uit.

Diagram waarin het aangepaste conversieprogramma voor gegevensbinding wordt weergegeven.

Om te herhalen, zijn standaardconversies mogelijk beschikbaar vanwege typeconversieprogramma's die aanwezig zijn in het type waaraan wordt gebonden. Dit gedrag is afhankelijk van welk type conversieprogramma's beschikbaar zijn in het doel. Als u twijfelt, maakt u uw eigen conversieprogramma.

Hier volgen enkele typische scenario's waarin het zinvol is om een gegevensconversieprogramma te implementeren:

  • Uw gegevens moeten anders worden weergegeven, afhankelijk van de cultuur. U kunt bijvoorbeeld een valutaconversieprogramma of een kalenderdatum/tijdconversieprogramma implementeren op basis van de conventies die in een bepaalde cultuur worden gebruikt.

  • De gegevens die worden gebruikt, zijn niet noodzakelijkerwijs bedoeld om de tekstwaarde van een eigenschap te wijzigen, maar zijn in plaats daarvan bedoeld om een andere waarde te wijzigen, zoals de bron voor een afbeelding of de kleur of stijl van de weergavetekst. Conversieprogramma's kunnen in dit geval worden gebruikt door de binding van een eigenschap te converteren die mogelijk niet geschikt lijkt te zijn, zoals het binden van een tekstveld aan de eigenschap Achtergrond van een tabelcel.

  • Meer dan één besturingselement of meerdere eigenschappen van besturingselementen zijn gebonden aan dezelfde gegevens. In dit geval kan de primaire binding alleen de tekst weergeven, terwijl andere bindingen specifieke weergaveproblemen verwerken, maar nog steeds dezelfde binding gebruiken als brongegevens.

  • Een doeleigenschap heeft een verzameling bindingen, die wordt aangeduid als MultiBinding. Voor MultiBindinggebruikt u een aangepaste IMultiValueConverter om een uiteindelijke waarde te produceren op basis van de waarden van de bindingen. De kleur kan bijvoorbeeld worden berekend op basis van rode, blauwe en groene waarden, die waarden uit dezelfde of verschillende bindingsbronobjecten kunnen zijn. Zie MultiBinding voor voorbeelden en informatie.

Binding met verzamelingen

Een bindingsbronobject kan worden behandeld als één object waarvan de eigenschappen gegevens bevatten of als een gegevensverzameling van polymorfe objecten die vaak zijn gegroepeerd (zoals het resultaat van een query naar een database). Tot nu toe hebben we alleen de binding met afzonderlijke objecten besproken. Het binden aan een gegevensverzameling is echter een veelvoorkomend scenario. Een veelvoorkomend scenario is bijvoorbeeld het gebruik van een ItemsControl, zoals een ListBox, ListViewof TreeView om een gegevensverzameling weer te geven, zoals in de app die wordt weergegeven in de sectie Wat is gegevensbinding.

Gelukkig is ons basisdiagram nog steeds van toepassing. Als u een ItemsControl aan een verzameling bindt, ziet het diagram er als volgt uit.

diagram waarin het object ItemsControl voor gegevensbinding wordt weergegeven.

Zoals in dit diagram wordt weergegeven, is ItemsControl.ItemsSource eigenschap de eigenschap die moet worden gebruikt om een ItemsControl te binden aan een verzamelingsobject. U kunt ItemsSource zien als de inhoud van de ItemsControl. De binding is OneWay omdat de eigenschap ItemsSource standaard ondersteuning biedt voor OneWay binding.

Hoe verzamelingen te implementeren

U kunt elke verzameling opsommen die de IEnumerable-interface implementeert. Als u echter dynamische bindingen wilt instellen zodat invoegingen of verwijderingen in de verzameling de gebruikersinterface automatisch bijwerken, moet de verzameling de INotifyCollectionChanged-interface implementeren. Deze interface maakt een gebeurtenis beschikbaar die moet worden gegenereerd wanneer de onderliggende verzameling verandert.

WPF biedt de ObservableCollection<T>-klasse, een ingebouwde implementatie van een gegevensverzameling die de INotifyCollectionChanged-interface beschikbaar maakt. Om het overdragen van gegevenswaarden van bronobjecten naar doelen volledig te ondersteunen, moet elk object in uw verzameling dat bindbare eigenschappen ondersteunt, ook de INotifyPropertyChanged-interface implementeren. Zie Overzicht van bindingsbronnenvoor meer informatie.

Voordat u uw eigen verzameling implementeert, kunt u overwegen om ObservableCollection<T> of een van de bestaande verzamelingsklassen te gebruiken, zoals List<T>, Collection<T>en BindingList<T>, onder andere. Als u een geavanceerd scenario hebt en uw eigen verzameling wilt implementeren, kunt u overwegen IListte gebruiken. Dit biedt een niet-algemene verzameling objecten die afzonderlijk kunnen worden geopend door de index en biedt zo de beste prestaties.

Weergaven van collecties

Zodra uw ItemsControl is gebonden aan een gegevensverzameling, kunt u de gegevens sorteren, filteren of groeperen. Hiervoor gebruikt u verzamelingsweergaven, die klassen zijn die de ICollectionView-interface implementeren.

Wat zijn verzamelingsweergaven?

Een verzamelingsweergave is een laag boven op een bindingsbronverzameling waarmee u door de bronverzameling kunt navigeren en weergeven op basis van sorteer-, filter- en groepsquery's, zonder dat u de onderliggende bronverzameling zelf hoeft te wijzigen. Een verzamelingsweergave onderhoudt ook een aanwijzer naar het huidige item in de verzameling. Als de bronverzameling de INotifyCollectionChanged-interface implementeert, worden de wijzigingen die door de CollectionChanged gebeurtenis worden aangebracht, doorgegeven aan de weergaven.

Omdat weergaven de onderliggende bronverzamelingen niet wijzigen, kan aan elke bronverzameling meerdere weergaven zijn gekoppeld. U hebt bijvoorbeeld een verzameling Taak--objecten. Met het gebruik van weergaven kunt u dezelfde gegevens op verschillende manieren weergeven. Aan de linkerkant van de pagina wilt u bijvoorbeeld taken weergeven die zijn gesorteerd op prioriteit en aan de rechterkant gegroepeerd op gebied.

Hoe maak je een weergave aan

Een manier om een weergave te maken en te gebruiken, is door het weergaveobject rechtstreeks te instantiëren en vervolgens te gebruiken als bindingsbron. Denk bijvoorbeeld aan de demo-app voor Demo van gegevensbinding app die wordt weergegeven in de sectie Wat is gegevensbinding. De app wordt zodanig geïmplementeerd dat de ListBox wordt gebonden aan een weergave van de gegevensverzameling in plaats van de gegevensverzameling rechtstreeks. Het volgende voorbeeld is afkomstig uit de demo app. De CollectionViewSource klasse is de XAML-proxy van een klasse die wordt overgenomen van CollectionView. In dit specifieke voorbeeld is de Source van de weergave gebonden aan de AuctionItems verzameling (van het type ObservableCollection<T>) van het huidige app-object.

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

De resource listingDataView fungeert vervolgens als de bindingsbron voor elementen in de app, zoals de ListBox.

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

Als u een andere weergave voor dezelfde verzameling wilt maken, kunt u een andere CollectionViewSource exemplaar maken en een andere x:Key naam geven.

In de volgende tabel ziet u welke weergavegegevenstypen worden gemaakt als de standaardverzamelingsweergave of door CollectionViewSource op basis van het type bronverzameling.

Type bronverzameling Verzamelingsweergavetype Notities
IEnumerable Een intern type op basis van CollectionView Kan items niet groeperen.
IList ListCollectionView Snelst.
IBindingList BindingListCollectionView

Een standaardweergave gebruiken

Het opgeven van een verzamelingsweergave als bindingsbron is een manier om een verzamelingsweergave te maken en te gebruiken. WPF maakt ook een standaardverzamelingsweergave voor elke verzameling die als bindingsbron wordt gebruikt. Als u rechtstreeks verbinding maakt met een verzameling, wordt WPF gekoppeld aan de standaardweergave. Deze standaardweergave wordt gedeeld door alle bindingen met dezelfde verzameling, dus een wijziging in een standaardweergave met één afhankelijk besturingselement of code (zoals sorteren of een wijziging in de huidige itemaanwijzer, die later wordt besproken), wordt doorgevoerd in alle andere bindingen met dezelfde verzameling.

Als u de standaardweergave wilt ophalen, gebruikt u de methode GetDefaultView. Zie voor een voorbeeld De standaardweergave van een gegevensset ophalen (.NET Framework).

Verzamelingsweergaven met ADO.NET DataTables

Om de prestaties te verbeteren, kunnen verzamelingsweergaven voor ADO.NET DataTable of DataView objecten sorteren en filteren delegeren aan de DataView, waardoor sorteren en filteren wordt gedeeld in alle verzamelingsweergaven van de gegevensbron. Als u wilt dat elke verzamelingsweergave onafhankelijk van elkaar kan sorteren en filteren, initialiseert u elke verzamelingsweergave met een eigen DataView-object.

Sorteren

Zoals eerder vermeld, kunnen weergaven een sorteervolgorde toepassen op een verzameling. Zoals deze bestaat in de onderliggende verzameling, hebben uw gegevens mogelijk al dan niet een relevante, inherente volgorde. Met de weergave van de verzameling kunt u een order opleggen of de standaardvolgorde wijzigen op basis van vergelijkingscriteria die u opgeeft. Omdat het een clientweergave van de gegevens is, is een veelvoorkomend scenario dat de gebruiker mogelijk kolommen met tabelgegevens wilt sorteren op basis van de waarde waarmee de kolom overeenkomt. Met behulp van weergaven kan deze door de gebruiker gestuurde sortering opnieuw worden toegepast, zonder wijzigingen aan te brengen in de onderliggende verzameling of zelfs om een nieuwe query uit te voeren voor de inhoud van de verzameling. Zie bijvoorbeeld Een GridView-kolom sorteren wanneer op een koptekst (.NET Framework)wordt geklikt.

In het volgende voorbeeld ziet u de sorteerlogica van de CheckBox 'Sorteren op categorie en datum' van de gebruikersinterface van de app in de sectie Wat is gegevensbinding.

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

Filteren

Weergaven kunnen ook een filter toepassen op een verzameling, zodat in de weergave slechts een bepaalde subset van de volledige verzameling wordt weergegeven. U kunt filteren op een voorwaarde in de gegevens. Zoals bijvoorbeeld wordt gedaan door de app in het gedeelte Wat is gegevensbinding, bevat de sectie CheckBox 'Alleen koopjes weergeven' logica om items te filteren die $ 25 of meer kosten. De volgende code wordt uitgevoerd om ShowOnlyBargainsFilter in te stellen als de Filter gebeurtenis-handler wanneer die CheckBox is geselecteerd.

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

De ShowOnlyBargainsFilter gebeurtenishandler heeft de volgende implementatie.

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

Als u een van de CollectionView klassen rechtstreeks in plaats van CollectionViewSourcegebruikt, gebruikt u de eigenschap Filter om een callback op te geven. Zie bijvoorbeeld Gegevens filteren in een weergave (.NET Framework).

Groepering

Met uitzondering van de interne klasse die een IEnumerable verzameling bekijkt, ondersteunen alle verzamelingsweergaven groeperen, waardoor de gebruiker de verzameling in de verzamelingsweergave kan partitioneren in logische groepen. De groepen kunnen expliciet zijn, waarbij de gebruiker een lijst met groepen levert of impliciet, waarbij de groepen dynamisch worden gegenereerd, afhankelijk van de gegevens.

In het volgende voorbeeld ziet u de logica van de CheckBox'Groeperen op categorie'.

// 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)

Zie Groepitems in een ListView die een GridView (.NET Framework) implementeertvoor een ander groepeervoorbeeld.

Huidige pointeren van items

Weergaven ondersteunen ook het concept van een actueel item. U kunt door de objecten in een verzamelingsweergave navigeren. Terwijl u navigeert, verplaatst u een itemaanwijzer waarmee u het object kunt ophalen dat zich op die specifieke locatie in de verzameling bevindt. Zie voor een voorbeeld Navigeren door de objecten in een Data CollectionView (.NET Framework).

Omdat WPF alleen verbinding maakt met een verzameling met behulp van een weergave (een weergave die u opgeeft of de standaardweergave van de verzameling), hebben alle bindingen met verzamelingen een huidige itemaanwijzer. Bij het binden aan een weergave wordt met het slashteken (/) in een Path waarde het huidige item van de weergave aangewezen. In het volgende voorbeeld is de gegevenscontext een verzamelingsweergave. De eerste regel verbindt zich met de verzameling. De tweede regel wordt gekoppeld aan het huidige item in de verzameling. De derde regel wordt gekoppeld aan de eigenschap Description van het huidige item in de verzameling.

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

De slash- en eigenschapsyntaxis kunnen ook worden gecombineerd om een hiërarchie van verzamelingen te doorlopen. In het volgende voorbeeld wordt er een koppeling gemaakt met het huidige item van een verzameling genaamd Offices, dat een eigenschap is van het huidige item van de bronverzameling.

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

De huidige itemaanwijzer kan worden beïnvloed door sorteer- of filterbewerkingen die op de verzameling worden toegepast. Als u sorteert, blijft de huidige itemaanwijzer op het laatste geselecteerde item behouden, maar de verzamelingsweergave wordt nu opnieuw geherstructureerd. (Misschien was het geselecteerde item aan het begin van de lijst eerder, maar nu bevindt het geselecteerde item zich mogelijk ergens in het midden.) Door te filteren blijft het geselecteerde item behouden als die selectie na het filteren in beeld blijft. Anders wordt de huidige itemaanwijzer ingesteld op het eerste item van de gefilterde verzamelingsweergave.

Meester-detailbindingsscenario

Het idee van een huidig item is niet alleen handig voor het navigeren van items in een verzameling, maar ook voor het bindingsscenario met hoofddetails. Houd rekening met de gebruikersinterface van de app in sectie Wat is gegevensbinding. In die app bepaalt de selectie in de ListBox de inhoud die wordt weergegeven in de ContentControl. Als u een ListBox item op een andere manier wilt plaatsen, worden in de ContentControl de details van het geselecteerde item weergegeven.

U kunt het master-detailscenario eenvoudig implementeren door twee of meer besturingselementen aan dezelfde weergave te binden. In het volgende voorbeeld uit de Gegevensbinding demo zie je de markeringen van ListBox en ContentControl op de app-gebruikersinterface in de sectie Wat is gegevensbinding.

<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"/>

U ziet dat beide besturingselementen zijn gebonden aan dezelfde bron, de listingDataView statische resource (zie de definitie van deze resource in de Een weergavesectie maken). Deze binding werkt omdat wanneer een object (in dit geval de ContentControl) is gebonden aan een verzamelingsweergave, deze automatisch wordt gekoppeld aan de CurrentItem van de weergave. De CollectionViewSource objecten synchroniseren automatisch valuta en selectie. Als uw lijstbesturingselement niet is gebonden aan een CollectionViewSource object, zoals in dit voorbeeld, moet u de eigenschap IsSynchronizedWithCurrentItem instellen op true zodat dit werkt.

Zie Binden aan een verzameling en informatie weergeven op basis van selectie (.NET Framework) en Gebruik het masterdetailpatroon met hiërarchische gegevens (.NET Framework)voor andere voorbeelden.

Mogelijk hebt u gemerkt dat in het bovenstaande voorbeeld een sjabloon wordt gebruikt. In feite worden de gegevens niet weergegeven zoals we willen zonder het gebruik van sjablonen (de sjabloon die expliciet wordt gebruikt door de ContentControl en de gegevens die impliciet door de ListBoxworden gebruikt). We gaan nu naar gegevenssjablonen in de volgende sectie.

Gegevenssjablonering

Zonder het gebruik van gegevenssjablonen ziet de gebruikersinterface van onze app in de sectie Voorbeeld van gegevensbinding er als volgt uit:

demo van gegevensbinding zonder gegevenssjablonen

Zoals wordt weergegeven in het voorbeeld in de vorige sectie, zijn zowel het besturingselement ListBox als het ContentControl gebonden aan het hele verzamelingsobject (of meer specifiek de weergave over het verzamelingsobject) van AuctionItems. Zonder specifieke instructies voor het weergeven van de gegevensverzameling, geeft de ListBox de tekenreeksweergave van elk object in de onderliggende verzameling weer en geeft de ContentControl de tekenreeksweergave weer van het object waaraan het is gebonden.

Om dit probleem op te lossen, definieert de app DataTemplates. Zoals wordt weergegeven in het voorbeeld in de vorige sectie, gebruikt de ContentControl expliciet de gegevenssjabloon detailsProductListingTemplate. Het besturingselement ListBox maakt impliciet gebruik van de volgende gegevenssjabloon bij het weergeven van de AuctionItem objecten in de verzameling.

<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>

Met het gebruik van deze twee DataTemplates wordt de resulterende gebruikersinterface weergegeven in de sectie Wat is gegevensbinding sectie. Zoals u in die schermopname kunt zien, kunt u naast het plaatsen van gegevens in uw besturingselementen, met DataTemplates aantrekkelijke visuals voor uw gegevens definiëren. DataTriggers worden bijvoorbeeld gebruikt in de bovenstaande DataTemplate zodat AuctionItems die de SpecialFeatures waarde van HighLight hebben, met een oranje rand en een ster worden weergegeven.

Zie het overzicht van gegevenssjablonen (.NET Framework)voor meer informatie over gegevenssjablonen.

Gegevensvalidatie

De meeste apps die gebruikersinvoer gebruiken, moeten validatielogica hebben om ervoor te zorgen dat de gebruiker de verwachte informatie heeft ingevoerd. De validatiecontroles kunnen worden gebaseerd op type-, bereik-, indelings- of andere app-specifieke vereisten. In deze sectie wordt beschreven hoe gegevensvalidatie werkt in WPF.

Validatieregels koppelen aan een binding

Met het WPF-gegevensbindingsmodel kunt u ValidationRules koppelen aan uw Binding-object. In het volgende voorbeeld wordt bijvoorbeeld een TextBox gekoppeld aan een eigenschap met de naam StartPrice en wordt een ExceptionValidationRule-object toegevoegd aan de eigenschap Binding.ValidationRules.

<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>

Een ValidationRule object controleert of de waarde van een eigenschap geldig is. WPF heeft twee typen ingebouwde ValidationRule-objecten:

U kunt ook uw eigen validatieregel maken door de ValidationRule klasse te gebruiken en de methode Validate te implementeren. In het volgende voorbeeld ziet u de regel die wordt gebruikt door de "Productvermelding toevoegen" "Begindatum" TextBox uit de sectie "Wat is gegevensbinding".

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

De StartDateEntryFormTextBox gebruikt dit FutureDateRule, zoals wordt weergegeven in het volgende voorbeeld.

<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>

Omdat de UpdateSourceTrigger waarde is PropertyChanged, werkt de bindingsengine de bronwaarde bij op elke toetsaanslag, wat betekent dat ook elke regel in de verzameling ValidationRules op elke toetsaanslag wordt gecontroleerd. We bespreken dit verder in de sectie Validatieproces.

Visuele feedback geven

Als de gebruiker een ongeldige waarde invoert, kunt u feedback geven over de fout in de gebruikersinterface van de app. Een manier om dergelijke feedback te geven is door de eigenschap Validation.ErrorTemplate gekoppeld aan een aangepaste ControlTemplatein te stellen. Zoals wordt weergegeven in de vorige subsectie, gebruikt de StartDateEntryFormTextBox een ErrorTemplate genaamd validationTemplate. In het volgende voorbeeld ziet u de definitie van validationTemplate.

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

Het AdornedElementPlaceholder element geeft aan waar het besturingselement moet worden geplaatst.

Daarnaast kunt u ook een ToolTip gebruiken om het foutbericht weer te geven. Zowel de StartDateEntryForm als de StartPriceEntryFormTextBoxgebruiken de stijl textStyleTextBox, waarmee een ToolTip wordt gemaakt waarin de foutmelding wordt weergegeven. In het volgende voorbeeld ziet u de definitie van textStyleTextBox. De gekoppelde eigenschap Validation.HasError wordt true wanneer een of meer bindingen op de eigenschappen van het afhankelijke element fout zijn.

<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>

Met de aangepaste ErrorTemplate en de ToolTipziet de StartDateEntryForm-TextBox er als volgt uit wanneer er een validatiefout optreedt.

validatiefout gegevensbinding voor datum

Als uw Binding validatieregels heeft gekoppeld, maar u geen ErrorTemplate specificeert op het gebonden besturingselement, wordt een standaard-ErrorTemplate gebruikt om gebruikers op de hoogte te stellen wanneer er een validatiefout optreedt. De standaard ErrorTemplate is een besturingssjabloon die een rode rand in de sierlaag definieert. Met de standaard-ErrorTemplate en de ToolTipziet de gebruikersinterface van de StartPriceEntryForm-TextBox er als volgt uit wanneer er een validatiefout optreedt.

fout bij validatie van gegevensbinding voor prijs

Zie de sectie Aangepaste dialoogvensters in de Dialoogvensters overzichtvoor een voorbeeld van hoe u logica kunt bieden voor het valideren van alle besturingselementen in een dialoogvenster.

Validatieproces

Validatie treedt meestal op wanneer de waarde van een doel wordt overgebracht naar de eigenschap bindingsbron. Deze overdracht vindt plaats op TwoWay en OneWayToSource bindingen. Om te herhalen, wat ervoor zorgt dat een bronupdate wordt veroorzaakt, is afhankelijk van de waarde van de eigenschap UpdateSourceTrigger, zoals beschreven in de sectie Wat bronupdates activeert sectie.

In de volgende items wordt het validatieproces beschreven. Als er op elk moment tijdens dit proces een validatiefout of een ander type fout optreedt, wordt het proces gestopt:

  1. De bindingsengine controleert of er aangepaste ValidationRule-objecten zijn gedefinieerd waarvan de ValidationStep is ingesteld op RawProposedValue voor die Binding. In dat geval wordt de Validate methode op elke ValidationRule aangeroepen totdat een van deze objecten een fout krijgt of totdat ze allemaal zijn verstreken.

  2. De bindingsengine roept vervolgens het conversieprogramma aan, indien aanwezig.

  3. Als het conversieprogramma slaagt, controleert de bindingsengine of er aangepaste ValidationRule-objecten zijn gedefinieerd waarvan de ValidationStep is ingesteld op ConvertedProposedValue voor die Binding, in welk geval de Validate methode wordt aangeroepen voor elke ValidationRule die ValidationStep is ingesteld op ConvertedProposedValue totdat een van deze een fout krijgt of totdat ze allemaal worden doorgegeven.

  4. De bindingsengine stelt de broneigenschap in.

  5. De bindings-engine controleert of er aangepaste ValidationRule-objecten zijn gedefinieerd waarvan de ValidationStep is ingesteld op UpdatedValue voor die Binding. In dat geval roept het de Validate-methode aan voor elke ValidationRule waarbij ValidationStep is ingesteld op UpdatedValue, totdat een van hen een fout tegenkomt of totdat ze allemaal slagen. Als een DataErrorValidationRule is gekoppeld aan een binding en de bijbehorende ValidationStep is ingesteld op de standaardwaarde, UpdatedValue, wordt de DataErrorValidationRule op dit moment gecontroleerd. Op dit moment wordt elke binding waarbij ValidatesOnDataErrors is ingesteld op true gecontroleerd.

  6. De bindingsengine controleert of er aangepaste ValidationRule-objecten zijn gedefinieerd waarvan de ValidationStep is ingesteld op CommittedValue voor die Binding. In dat geval roept het de Validate-methode aan voor elke ValidationRule waarvan ValidationStep is ingesteld op CommittedValue, totdat een daarvan een fout ervaart of totdat ze allemaal slagen.

Als een ValidationRule op enig moment tijdens dit proces niet slaagt, creëert de bindingsengine een ValidationError-object en voegt het toe aan de Validation.Errors-verzameling van het gebonden element. Voordat de bindingsengine de ValidationRule objecten in een bepaalde stap draait, worden alle ValidationError verwijderd die in die stap aan de aan de Validation.Errors gekoppelde eigenschap van het gebonden element zijn toegevoegd. Als bijvoorbeeld een ValidationRule waarvan de ValidationStep is ingesteld op UpdatedValue mislukt, verwijdert de bindingsengine de volgende keer dat het validatieproces plaatsvindt, die ValidationError onmiddellijk voordat het een ValidationRule aanroept die is ingesteld op UpdatedValuemet ValidationStep.

Wanneer Validation.Errors niet leeg is, wordt de gekoppelde eigenschap Validation.HasError van het element ingesteld op true. Als de eigenschap NotifyOnValidationError van de Binding is ingesteld op true, dan genereert de bindingsengine ook de Validation.Error gekoppelde gebeurtenis bij het element.

Houd er ook rekening mee dat een geldige waardeoverdracht in een van beide richtingen (doel naar bron of bron naar doel) de aan Validation.Errors gekoppelde eigenschap wist.

Als aan de binding een ExceptionValidationRule is gekoppeld of als de eigenschap ValidatesOnExceptions is ingesteld op true en er een uitzondering wordt gegenereerd wanneer de bindingsengine de bron instelt, controleert de bindingsengine of er een UpdateSourceExceptionFilteris. U kunt de UpdateSourceExceptionFilter callback gebruiken om een aangepaste handler te bieden voor het afhandelen van uitzonderingen. Als een UpdateSourceExceptionFilter niet is opgegeven in de Binding, maakt de bindingsengine een ValidationError met de uitzondering en voegt deze toe aan de Validation.Errors verzameling van het afhankelijke element.

Foutopsporingsmechanisme

U kunt de gekoppelde eigenschap instellen PresentationTraceSources.TraceLevel op een bindingsobject om informatie te ontvangen over de status van een specifieke binding.

Zie ook