Přehled datových vazeb ve WPF

Datová vazba ve WPF (Windows Presentation Foundation) je jednoduchý a konzistentní způsob, jakým aplikace můžou zobrazovat data a pracovat s nimi. Prvky mohou být vázány na data z různých zdrojů dat ve formě objektů .NET a XML. Jakékoli ContentControl, například Button a jakékoli ItemsControl, například ListBox a ListView, mají integrované funkce, které umožňují flexibilní použití stylů jednotlivých datových položek nebo kolekcí datových položek. Nad daty lze generovat zobrazení řazení, filtrování a seskupení.

Funkce datových vazeb ve WPF má oproti tradičním modelům několik výhod, včetně vlastní podpory datových vazeb širokou škálou vlastností, flexibilní reprezentací dat v uživatelském rozhraní a čisté oddělení obchodní logiky od uživatelského rozhraní.

Tento článek nejprve popisuje základní koncepty datové vazby WPF a pak se zabývá používáním třídy Binding a dalších funkcí datové vazby.

Co je datová vazba?

Datová vazba je proces, který vytvoří propojení mezi uživatelským rozhraním aplikace a daty, která zobrazuje. Pokud má vazba správné nastavení a data poskytují správná oznámení při změně jejich hodnoty, elementy vázané na data se automaticky změní. Datová vazba může také znamenat, že pokud se změní vnější reprezentace dat v elementu, mohou být podkladová data automaticky aktualizována tak, aby odrážela tuto změnu. Pokud například uživatel upraví hodnotu v elementu TextBox, hodnota podkladových dat se automaticky aktualizuje tak, aby tuto změnu odrážela.

Typickým použitím datové vazby je umístění serverových nebo místních konfiguračních dat do formulářů nebo jiných ovládacích prvků uživatelského rozhraní. Ve WPF je tento koncept rozšířen tak, aby zahrnoval vazbu široké škály vlastností na různé zdroje dat. Ve WPF mohou být vlastnosti závislostí elementů vázané na objekty .NET (včetně objektů ADO.NET nebo objektů přidružených webovým službám a webovým vlastnostem) a data XML.

Příklad datové vazby najdete v následujícím uživatelském rozhraní aplikace z ukázky datové vazby, která zobrazuje seznam položek aukce.

Data binding sample screenshot

Aplikace ukazuje následující funkce datové vazby:

  • Obsah ovládacího prvku ListBox je vázán na kolekci objektů AuctionItem. Objekt AukčníItem má vlastnosti, jako je Description, StartPrice, StartDate, Category, SpecialFeatures atd.

  • Data (objekty AuctionItem) zobrazená v ListBox mají šablonu, aby se popis a aktuální cena zobrazovaly pro každou položku. Šablona se vytvoří pomocí DataTemplate. Kromě toho vzhled jednotlivých položek závisí na hodnotě SpecialFeatures zobrazeného objektu AuctionItem. Pokud je hodnota SpecialFeatures objektu AuctionItemColor, položka má modré ohraničení. Pokud je hodnota Highlight, má položka oranžové ohraničení a hvězdičku. Část Šablonování dat poskytuje informace o šablonách dat.

  • Uživatel může data seskupit, filtrovat nebo řadit pomocí zadaného CheckBoxes. Na obrázku výše jsou vybrány možnosti Seskupit podle kategorie a Řadit podle kategorie a dataCheckBoxes. Možná jste si všimli, že se data seskupují podle kategorie produktu a názvu kategorie je v abecedním pořadí. Z obrázku je obtížné si všimnout, ale položky jsou také seřazené podle počátečního data v rámci každé kategorie. Řazení se provádí pomocí zobrazení kolekce. Část Vazby na kolekce popisuje zobrazení kolekcí.

  • Když uživatel vybere položku, ContentControl zobrazí se podrobnosti o vybrané položce. Toto prostředí se nazývá scénář seznam-podrobnosti. Část se scénářem seznam-podrobnosti obsahuje informace o tomto typu vazby.

  • Typ vlastnosti StartDate je DateTime a vrací datum, které zahrnuje čas v milisekundách. V této aplikaci byl použit vlastní převaděč, aby se zobrazil kratší řetězec kalendářního data. Část Převod dat obsahuje informace o převaděčích.

Když uživatel vybere tlačítko Přidat produkt, zobrazí se následující formulář.

Add Product Listing page

Uživatel může upravit pole ve formuláři, zobrazit náhled výpisu produktů pomocí krátkých nebo podrobných podoken náhledu a vybrat Submit pro přidání nového výpisu produktů. Všechna existující nastavení seskupení, filtrování a řazení se použijí pro novou položku. V tomto konkrétním případě se položka zadaná na obrázku výše zobrazí jako druhá položka v kategorii Počítač.

Na tomto obrázku se nezobrazuje ověřovací logika zadaná v počátečním datuTextBox. Pokud uživatel zadá neplatné datum (neplatný formát nebo datum v minulosti), zobrazí se uživateli oznámení s ToolTip červeným vykřičníkem vedle TextBox. Část Ověření dat popisuje, jak vytvořit logiku ověřování.

Než se začneme věnovat různým funkcím datových vazeb uvedených výše, podíváme se nejprve na základní koncepty, které jsou důležité pro pochopení datové vazby WPF.

Základní koncepty datových vazeb

Bez ohledu na to, jaký prvek vytváříte vazby a povahu zdroje dat, každá vazba vždy sleduje model znázorněný na následujícím obrázku.

Diagram that shows the basic data binding model.

Jak je na obrázku vidět, datová vazba je v podstatě mostem mezi cílem vazby a zdrojem vazby. Obrázek představuje následující základní koncepty datových vazeb WPF:

  • Každá vazba má obvykle čtyři komponenty:

    • Objekt cíle vazby.
    • Vlastnost cíle.
    • Zdroj vazby.
    • Cestu k hodnotě ve zdroji vazby, která se má použít.

    Pokud například chcete svázat obsah TextBoxEmployee.Name vlastnosti, je cílovým objektem TextBoxvlastnost , cílovou vlastností je Text vlastnost, hodnota, kterou chcete použít, a zdrojovým objektem je Employee objekt.

  • Vlastnost cíle musí být vlastnost závislosti. Většina vlastností UIElement jsou vlastnosti závislostí a většina vlastností závislostí, kromě těch pouze pro čtení, podporuje datovou vazbu ve výchozím nastavení. (Pouze typy odvozené z DependencyObject mohou definovat vlastnosti závislosti; a všechny UIElement typy odvozené od DependencyObject.)

  • I když se na obrázku nezobrazuje, je třeba poznamenat, že zdrojový objekt vazby není omezen na vlastní objekt .NET. Datová vazba WPF podporuje data ve formě objektů .NET a XML. Abychom uvedli několik příkladů, váš zdroj vazby může být UIElement, libovolný objekt seznamu, objekt ADO.NET nebo objekt webových služeb, nebo XmlNode obsahující vaše data XML. Další informace najdete v přehledu zdrojů vazeb.

Je důležité si uvědomit, že při vytváření vazby vytváříte vazbu cíl vazby ke zdroji vazby. Pokud například zobrazujete některá podkladová data XML v ListBox datové vazbě pomocí datové vazby, vytváříte vazbu ListBox s daty XML.

K vytvoření vazby použijete objekt Binding. Zbytek tohoto článku popisuje koncepty spojené s objektem Binding a některé jeho vlastnosti a použití.

Směr toku dat

Jak je naznačeno šipkou na předchozím obrázku, tok dat vazby může přecházet z cíle vazby do zdroje vazby (například zdrojová hodnota se změní, když uživatel upraví hodnotu TextBox) nebo ze zdroje vazby do cíle vazby (například obsah TextBox se aktualizuje změnami ve zdroji vazby), za předpokladu, že zdroj vazby poskytuje správná oznámení.

Můžete chtít, aby vaše aplikace umožňovala uživatelům změnit data a rozšířit je zpět do zdrojového objektu. Nebo nemusíte chtít uživatelům povolit, aby zdrojová data aktualizovali. Tok dat můžete řídit nastavením Binding.Mode.

Tento obrázek znázorňuje různé typy toku dat:

Data binding data flow

  • Vazba OneWay způsobí, že změny vlastnosti zdroje automaticky aktualizují vlastnost cíle, ale změny vlastnosti cíle se nešíří zpět do vlastnosti zdroje. Tento typ vazby je vhodný, pokud je vázaný ovládací prvek implicitně jen pro čtení. Můžete například vytvořit vazbu na zdroj, jako je burzovní pole, nebo možná vlastnost vašeho cíle nemá k dispozici žádné rozhraní ovládacího prvku pro provádění změn, jako je například barva pozadí vázaná na data tabulky. Pokud není potřeba monitorovat změny cílové vlastnosti, použití OneWay režimu vazby zabrání režii TwoWay režimu vazby.

  • Vazba TwoWay způsobí, že se změny vlastnosti zdroje nebo vlastnosti cíle navzájem automaticky aktualizují. Tento typ vazby je vhodný pro upravitelné formuláře nebo jiné plně interaktivní scénáře uživatelského rozhraní. Většina vlastností je výchozí pro OneWay vazbu, ale některé vlastnosti závislostí (obvykle vlastnosti ovládacích prvků, které lze upravovat uživatelem, jako TextBox.Textje checkBox.IsChecked) ve výchozím nastavení vazbyTwoWay. Programový způsob, jak určit, jestli je vlastnost závislosti ve výchozím nastavení jednosměrnou nebo obousměrnou vazbou, je získat metadata vlastnosti s DependencyProperty.GetMetadata a pak zkontrolovat logickou hodnotu vlastnosti FrameworkPropertyMetadata.BindsTwoWayByDefault.

  • OneWayToSource je obrácená vazba OneWay, aktualizuje vlastnost zdroje při změně vlastnosti cíle. Jedním z ukázkových scénářů je, že potřebujete pouze znovu vyhodnotit hodnotu zdroje z uživatelského rozhraní.

  • Není znázorněno na obrázku je OneTime vazba, která způsobí, že zdrojová vlastnost inicializuje cílovou vlastnost, ale nerozšíruje následné změny. Pokud se změní kontext dat nebo objekt v kontextu dat, změna se neprojeví ve vlastnosti cíle. Tento typ vazby je vhodný, pokud je snímek aktuálního stavu správný nebo jsou data skutečně statická. Tento typ vazby je také užitečný, pokud chcete inicializovat cílovou vlastnost s určitou hodnotou ze zdrojové vlastnosti a kontext dat není předem znám. Tento režim je v podstatě jednodušší forma vazby OneWay , která poskytuje lepší výkon v případech, kdy se zdrojová hodnota nezmění.

Aby bylo možné zjistit změny zdroje (týkající se vazeb OneWay a TwoWay), musí zdroj implementovat vhodný mechanismus oznámení změny vlastnosti, jako je například INotifyPropertyChanged. Viz Postupy: Implementace oznámení o změně vlastnosti pro příklad INotifyPropertyChanged implementace.

Vlastnost Binding.Mode poskytuje další informace o režimech vazby a příklad toho, jak určit směr vazby.

Co aktivuje aktualizace zdroje

Vazby, které jsou TwoWay nebo OneWayToSource, naslouchají změnám ve vlastnosti cíle a šíří je zpět do zdroje, což se označuje jako aktualizace zdroje. Můžete například upravit text textového pole, aby se změnila podkladová hodnota zdroje.

Aktualizuje se ale zdrojová hodnota při úpravách textu nebo po dokončení úprav textu a ovládací prvek ztratí fokus? Vlastnost Binding.UpdateSourceTrigger určuje, co aktivuje aktualizaci zdroje. Tečky šipek vpravo na následujícím obrázku znázorňují roli vlastnosti Binding.UpdateSourceTrigger.

Diagram that shows the role of the UpdateSourceTrigger property.

V případě, že hodnota UpdateSourceTrigger je UpdateSourceTrigger.PropertyChanged, pak hodnota odkazovaná šipkou vpravo TwoWay nebo vazby OneWayToSource se aktualizuje, jakmile se vlastnost cíle změní. V případě, že hodnota UpdateSourceTrigger je ale LostFocus, potom se daná hodnota aktualizuje novou hodnotou, pouze když hodnota cíle ztratí fokus.

Podobně jako u vlastnosti Mode mají různé vlastnosti závislostí různé výchozí hodnoty UpdateSourceTrigger. Výchozí hodnota pro většinu vlastností závislosti je PropertyChanged, zatímco TextBox.Text vlastnost má výchozí hodnotu LostFocus. PropertyChanged znamená, že ke zdrojovým aktualizacím obvykle dochází vždy, když se cílová vlastnost změní. Okamžité změny jsou v pořádku pro zaškrtávací políčka a další jednoduché ovládací prvky. V případě textových polí ale aktualizace po každém stisknutí klávesy může snížit výkon a odepřít uživateli obvyklou příležitost vymazat a opravit chyby při psaní, než novou hodnotu potvrdí.

Informace o tom, jak najít výchozí hodnotu vlastnosti závislosti, najdete na stránce vlastnosti UpdateSourceTrigger.

Následující tabulka poskytuje ukázkový scénář pro každou hodnotu UpdateSourceTrigger používající TextBox jako příklad.

Hodnota UpdateSourceTrigger Když se hodnota zdroje aktualizuje Ukázkový scénář pro TextBox (textové pole)
LostFocus (výchozí pro TextBox.Text) Když ovládací prvek TextBox ztratí fokus. TextBox, který je přidružený ověřovací logice (viz Ověření dat níže).
PropertyChanged Při psaní do TextBox. Ovládací prvky TextBox v okně chatovací místnosti.
Explicit Když aplikace volá UpdateSource. Ovládací prvky TextBox v upravitelném formuláři (aktualizují zdrojové hodnoty pouze tehdy, když uživatel klikne na tlačítko Odeslat).

Příklad najdete v tématu Postupy: Řízení, když text TextBox aktualizuje zdroj.

Vytvoření vazby

Zopakujme si některé koncepty probrané v předchozích částech, vazbu vytváříte pomocí objektu Binding a každá vazba má obvykle čtyři součásti: cíl vazby, vlastnost cíle, zdroj vazby a cestu ke zdrojové hodnotě, kterou chcete použít. Tato část popisuje, jak nastavit vazbu.

Představte si následující příklad, ve kterém je objekt zdroje vazby třída MyData definovaná v oboru názvů SDKSample. Pro demonstrační účely má třída MyData vlastnost řetězce s názvem ColorName, jejíž hodnota je nastavena na „Red“. Tento příklad tedy vygeneruje tlačítko s červeným pozadím.

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

Další informace o syntaxi deklarace vazby a příklady nastavení vazby v kódu naleznete v tématu Přehled deklarací vazeb.

Pokud tento příklad použijeme u našeho základního diagramu, bude výsledný obrázek vypadat takto. Tento obrázek popisuje vazbu OneWay, protože vlastnost Background ve výchozím nastavení podporuje vazbu OneWay.

Diagram that shows the data binding Background property.

Možná vás zajímá, proč tato vazba funguje, i když je vlastnost ColorName typu řetězec, zatímco vlastnost Background je typu Brush. Tato vazba používá výchozí převod typů, který je popsán v části Převod dat.

Určení zdroje vazby

Všimněte si, že v předchozím příkladu je zdroj vazby určen nastavením vlastnosti DockPanel.DataContext. Button potom zdědí hodnotu DataContext ze svého nadřazeného prvku DockPanel. Zopakujme si, že objekt zdroje vazby je jednou ze čtyř nezbytných součástí vazby. Proto bez zadání zdrojového objektu vazby by vazba nic neudělá.

Existuje několik způsobů, jak určit objekt zdroje vazby. DataContext Použití vlastnosti u nadřazeného elementu je užitečné, pokud vytváříte vazbu více vlastností do stejného zdroje. Někdy ale může být vhodnější určit zdroj vazby u jednotlivých deklarací vazeb. V předchozím příkladu můžete místo použití vlastnosti DataContext určit zdroj vazby nastavením vlastnosti Binding.Source přímo u deklarace vazby tlačítka jako v následujícím příkladu.

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

Kromě nastavení vlastnosti DataContext přímo u elementu, zdědění hodnoty DataContext z nadřazeného objektu (například tlačítka v prvním příkladu) a explicitního určení zdroje vazby nastavením vlastnosti Binding.Source u vazby (například tlačítko poslední příklad), můžete k určení zdroje vazby použít také vlastnost Binding.ElementName nebo vlastnost Binding.RelativeSource. Vlastnost ElementName je užitečná, když vytváříte vazbu na jiné prvky v aplikaci, například když používáte posuvník k úpravě šířky tlačítka. Vlastnost RelativeSource je užitečná, když je vazba zadána v ControlTemplate nebo Style. Další informace naleznete v tématu Postupy: Určení zdroje vazby.

Určení cesty k hodnotě

Pokud je zdrojem vazby objekt, použijete vlastnost Binding.Path, abyste určili hodnotu, která se má použít pro vaši vazbu. Pokud vytváříte vazbu na data XML, použijete Binding.XPath vlastnost k určení hodnoty. V některých případech se může použít vlastnost Path i pro data XML. Pokud například chcete získat přístup k vlastnosti Name vráceného XmlNode (výsledek dotazu XPath), měli byste kromě vlastnosti XPath použít také vlastnost Path.

Pokud chcete získat další informace, podívejte se na vlastnosti Path a XPath.

Ačkoli jsme zdůraznili, že Path k hodnotě, kterou chcete použít, je jednou ze čtyř nezbytných součástí vazby, ve scénářích, kde chcete vytvořit vazbu na celý objekt, bude použitá hodnota stejná jako objekt zdroje vazby. V těchto případech se použije k tomu, aby neurčovala Pathhodnotu . Představte si následující příklad.

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

Výše uvedený příklad používá prázdnou syntaxi vazby: {Binding}. V tomto případě ListBox dědí DataContext z nadřazeného elementu DockPanel (v tomto příkladu není znázorněn). Pokud není zadána cesta, výchozí hodnota je vytvořit vazbu na celý objekt. V tomto příkladu byla tedy cesta vynechána, protože vytváříme vazbu vlastnosti ItemsSource na celý objekt. (Podrobné informace najdete v části Vazby na kolekce.)

Kromě vazby na kolekci je tento scénář užitečný také v případě, že chcete vytvořit vazbu na celý objekt, nikoli pouze na jednu vlastnost objektu. Pokud je například zdrojový objekt typu String, můžete jednoduše chtít vytvořit vazbu na samotný řetězec. Dalším běžným scénářem je, že chcete vytvořit vazbu elementu na objekt s několika vlastnostmi.

Možná budete muset použít vlastní logiku, aby data byla pro vlastnost vašeho cíle smysluplná. Vlastní logika může být ve formě vlastního převaděče, pokud neexistuje výchozí převod typu. Informace o převaděčích najdete v tématu Převod dat.

Vazby a BindingExpression

Než se seznámíte s dalšími funkcemi a používáním datových vazeb, je užitečné zavést BindingExpression třídu. Jak jste viděli v předchozích částech, třída Binding je třída vysoké úrovně pro deklaraci vazby, poskytuje mnoho vlastností, které umožňují určit vlastnosti vazby. Související třída BindingExpression je podkladový objekt, který udržuje spojení mezi zdrojem a cílem. Vazba obsahuje všechny informace, které lze sdílet napříč několika výrazy vazby. BindingExpression je výraz instance, který nelze sdílet a který obsahuje všechny informace o instanci pro Binding.

Vezměte v úvahu následující příklad, kde myDataObject je instance třídy MyData, myBinding je objekt zdroje Binding a MyData je definovaná třída, která obsahuje vlastnost řetězce s názvem ColorName. Tento příklad vytvoří vazbu textového obsahu myText, instance TextBlock, na 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)

Pomocí stejného objektu myBinding můžete vytvořit další vazby. Objekt myBinding můžete například použít k vytvoření vazby textového obsahu zaškrtávacího políčka na ColorName. V tomto scénáři budou existovat dvě instance BindingExpression sdílejícího objekt myBinding.

Objekt BindingExpression je vrácen voláním GetBindingExpression u objektu vázaného na data. Následující články představují některá použití třídy BindingExpression:

Převod dat

V části Vytvoření vazby je tlačítko červené, protože jeho Background vlastnost je vázána na řetězcovou vlastnost s hodnotou "Red". Tato hodnota řetězce funguje, protože převaděč typů je u typu Brush přítomen, aby hodnotu řetězce převedl na Brush.

Přidání těchto informací na obrázek v části Vytvoření vazby vypadá takto.

Diagram that shows the data binding Default property.

Co když ale váš objekt zdroje vazby nemá vlastnost typu řetězec a jeho vlastnost Color je typu Color? Aby v takovém případě vazba fungovala, musíte nejprve změnit hodnotu vlastnosti Color na něco, co vlastnost Background přijímá. Budete muset vytvořit vlastní převaděč prostřednictvím implementace rozhraní IValueConverter, jako v následujícím příkladu.

[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

Další informace naleznete v tématu IValueConverter.

Vlastní převaděč se teď používá místo výchozího převodu a náš diagram vypadá takto.

Diagram that shows the data binding custom converter.

Zopakujme si, že výchozí převody mohou být dostupné díky přítomnosti převaděčů typů v typu, ke kterému se vazba vytváří. Toto chování bude záviset na tom, které převaděče typů jsou v cíli k dispozici. Pokud máte pochybnosti, vytvořte si vlastní převaděč.

Tady jsou některé typické scénáře, ve kterých je implementace převaděče data vhodná:

  • Vaše data by se měla v závislosti na jazykové verzi zobrazovat odlišně. Můžete například chtít implementovat převaděč měny nebo převaděč kalendářního data a času na základě konvencí používaných v určité jazykové verzi.

  • Použitá data nemusí nutně změnit textovou hodnotu vlastnosti, ale místo toho je určena ke změně jiné hodnoty, například zdroje obrázku nebo barvy nebo stylu zobrazovaného textu. Převaděče lze v této instanci použít prostřednictvím převodu vazby vlastnosti, která se nemusí zdát vhodná, například vytvořením vazby textového pole na vlastnost Background buňky tabulky.

  • Více než jeden ovládací prvek nebo více vlastností ovládacích prvků je vázáno na stejná data. V tomto případě může primární vazba jenom zobrazit text, zatímco jiné vazby zpracovávají konkrétní problémy se zobrazením, ale přitom jako zdrojové informace stále používají stejnou vazbu.

  • Vlastnost cíle má kolekci vazeb, které se označují jako MultiBinding. Pro MultiBinding použijete vlastní IMultiValueConverter, abyste vytvořili konečnou hodnotu z hodnot vazeb. Například barvu lze vypočítat z červených, modrých a zelených hodnot, což můžou být hodnoty ze stejných nebo jiných objektů zdroje vazby. Informace a příklady najdete v části MultiBinding.

Vazby na kolekce

Objekt zdroje vazby lze považovat za jeden objekt, jehož vlastnosti obsahují data, nebo za kolekci dat polymorfních objektů, které jsou často seskupeny dohromady (například výsledek dotazu do databáze). Zatím jsme se bavili pouze o vytváření vazby na jednotlivé objekty. Vazba na kolekci dat je ale běžným scénářem. Běžným scénářem je například použití ItemsControl typu ListBox, ListView nebo TreeView k zobrazení kolekce dat, například v aplikaci uvedené v části Co je datová vazba.

Naštěstí stále platí náš základní diagram. Pokud vytváříte vazbu ItemsControl na kolekci, diagram vypadá takto.

Diagram that shows the data binding ItemsControl object.

Jak je znázorněno v tomto diagramu, pokud chcete vytvořit vazbu ItemsControl na objekt kolekce, musíte použít vlastnost ItemsControl.ItemsSource. ItemsSource si můžete představit jako obsah ItemsControl. Vazba je OneWay, protože vlastnost ItemsSource ve výchozím nastavení podporuje vazbu OneWay.

Postup implementace kolekcí

Můžete vytvořit výčet všech kolekcí, které implementují rozhraní IEnumerable. Pokud ale chcete nastavit dynamické vazby tak, aby vložení nebo odstranění v kolekci automaticky aktualizovalo uživatelské rozhraní, musí kolekce implementovat rozhraní INotifyCollectionChanged. Toto rozhraní zveřejňuje událost, která by měla být vyvolána při každé změně podkladové kolekce.

WPF poskytuje třídu ObservableCollection<T>, což je integrovaná implementace kolekce dat, která zveřejňuje rozhraní INotifyCollectionChanged. Aby bylo možné plně podporovat přenos hodnot dat ze zdrojových objektů do cílů, musí každý objekt v kolekci, který podporuje vlastnosti s možností vazeb, implementovat také rozhraní INotifyPropertyChanged. Další informace najdete v přehledu zdrojů vazeb.

Před implementací vlastní kolekce zvažte použití ObservableCollection<T> nebo některé ze stávajících tříd kolekcí, například List<T>, Collection<T>, BindingList<T> a dalších. Pokud máte pokročilý scénář a chcete implementovat vlastní kolekci, zvažte použití IList, který poskytuje neobecnou kolekci objektů, ke kterým může index přistupovat jednotlivě a poskytuje tak nejlepší výkon.

Zobrazení kolekcí

Jakmile je objekt ItemsControl vázaný na kolekci dat, můžete chtít data řadit, filtrovat nebo seskupit. K tomu použijete zobrazení kolekcí, což jsou třídy, které implementují rozhraní ICollectionView.

Co jsou zobrazení kolekcí?

Zobrazení kolekce je vrstva nad kolekcí zdrojů vazby, která umožňuje procházet a zobrazovat kolekci zdrojů na základě řazení, filtrování a seskupení dotazů, aniž byste museli měnit samotnou podkladovou kolekci zdrojů. Zobrazení kolekce také udržuje ukazatel na aktuální položce v kolekci. Pokud kolekce zdrojů implementuje rozhraní INotifyCollectionChanged, změny vyvolané událostí CollectionChanged se rozšíří do zobrazení.

Vzhledem k tomu, že zobrazení nemění podkladové kolekce zdrojů, může mít každá kolekce zdrojů přidruženo více zobrazení. Můžete mít například kolekci objektů Task. Pomocí zobrazení můžete stejná data zobrazit různými způsoby. Na levé straně stránky můžete například chtít zobrazit úkoly seřazené podle priority a na pravé straně seskupené podle oblasti.

Postup vytvoření zobrazení

Jedním ze způsobů, jak vytvořit a použít zobrazení, je vytvořit přímo instanci objektu zobrazení a pak ji použít jako zdroj vazby. Představte si například ukázkové aplikace datové vazby zobrazenou v části Co je datová vazba. Aplikace je implementovaná tak, aby ListBox vytvořil vazbu na zobrazení kolekce dat, nikoli přímo na kolekci dat. Následující příklad se extrahuje z ukázkové aplikace datové vazby. Třída CollectionViewSource je XAML proxy třídy, která dědí z CollectionView. V tomto konkrétním příkladu je Source zobrazení vázaný na kolekci AuctionItems (typu ObservableCollection<T>) aktuálního objektu aplikace.

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

listingDataView prostředku pak slouží jako zdroj vazby pro elementy v aplikaci, jako je například ListBox.

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

Pokud chcete vytvořit další zobrazení pro stejnou kolekci, můžete vytvořit jinou instanci CollectionViewSource a dát jí jiný název x:Key.

Následující tabulka ukazuje, jaké datové typy zobrazení se vytvářejí jako výchozí zobrazení kolekce nebo podle CollectionViewSource na základě typu kolekce zdrojů.

Typ kolekce zdrojů Typ zobrazení kolekce Notes
IEnumerable Interní typ založený na CollectionView Položky nelze seskupit.
IList ListCollectionView Nejrychlejší.
IBindingList BindingListCollectionView

Použití výchozího zobrazení

Určení zobrazení kolekce jako zdroje vazeb je jedním ze způsobů, jak vytvořit a použít zobrazení kolekce. WPF také vytvoří výchozí zobrazení kolekce pro každou kolekci používanou jako zdroj vazby. Pokud vytvoříte vazbu přímo na kolekci, WPF vytvoří vazbu na její výchozí zobrazení. Toto výchozí zobrazení je sdíleno všemi vazbami na stejnou kolekci, takže změna provedené ve výchozím zobrazení jedním vázaným ovládacím prvkem nebo kódem (například řazením nebo změnou ukazatele aktuální položky, viz další části) se projeví ve všech ostatních vazbách na stejnou kolekci.

Pokud chcete získat výchozí zobrazení, použijte metodu GetDefaultView. Příklad najdete v tématu Získání výchozího zobrazení kolekce dat.

Zobrazení kolekcí s datovými tabulkami ADO.NET

Za účelem zlepšení výkonu delegují zobrazení kolekce pro ADO.NET DataTable nebo objektyDataView řazení a filtrování na DataView, což způsobí, že se řazení a filtrování sdílí napříč všemi zobrazeními kolekcí zdroje dat. Pokud chcete každému zobrazení kolekce povolit nezávislé řazení a filtrování, inicializujte každé zobrazení kolekce s jeho vlastním objektem DataView.

Třídění

Jak už bylo zmíněno dříve, zobrazení mohou u kolekce použít pořadí řazení. Vzhledem k tomu, že existují v podkladové kolekci, vaše data mohou a nemusí mít relevantní základní pořadí. Zobrazení kolekce umožňuje vynutit pořadí, nebo změnit výchozí pořadí, na základě vámi zadaných kritérií porovnání. Vzhledem k tomu, že se jedná o zobrazení dat na základě klienta, může uživatel chtít řadit sloupce tabulkových dat podle hodnoty, kterou sloupec odpovídá. Pomocí zobrazení lze toto uživatelem řízené řazení použít, aniž byste museli provádět změny v podkladové kolekci nebo se dokonce museli znovu dotazovat na obsah kolekce. Příklad najdete v tématu Řazení sloupce GridView po kliknutí na záhlaví.

Následující příklad ukazuje logiku řazení „Řadit podle kategorie a data“ CheckBox uživatelského rozhraní aplikace v části Co je datová vazba.

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

Filtrování

Zobrazení dále mohou na kolekci použít filtr, tak aby zobrazení zobrazovalo pouze určitou podmnožinu celé kolekce. V datech můžete filtrovat pomocí podmínky. Jak to například dělá aplikace v části Co je datová vazba. „Show only bargains“ CheckBox obsahuje logiku pro filtrování položek, které stojí 25 USD nebo více. Následující kód se spustí za účelem nastavení ShowOnlyBargainsFilter jako obslužné rutiny události Filter při výběru CheckBox.

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

Obslužná rutina události ShowOnlyBargainsFilter má následující implementaci.

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

Pokud používáte jednu z CollectionView tříd přímo místo CollectionViewSource, byste použili Filter vlastnost k určení zpětného volání. Příklad najdete v tématu Filtrování dat v zobrazení.

Seskupení

Kromě interní třídy, která zobrazuje kolekci IEnumerable, podporují všechna zobrazení kolekcí seskupení, což uživateli umožňuje rozdělit kolekci v zobrazení kolekce do logických skupin. Skupiny můžou být explicitní, kde uživatel poskytne seznam skupin, nebo implicitní, kde se skupiny generují dynamicky v závislosti na datech.

Následující příklad ukazuje logiku „seskupení podle kategorie“ 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)

Další příklad seskupení naleznete v části Položky skupiny v ListView, který implementuje GridView.

Ukazatele aktuální položky

Zobrazení také podporují pojem aktuální položky. Objekty můžete procházet v zobrazení kolekce. Při procházení přesouváte ukazatel položky, který umožňuje načíst objekt, který existuje v daném umístění v kolekci. Příklad naleznete v části Procházet objekty v objektu CollectionView.

Vzhledem k tomu, že WPF vytvoří vazbu na kolekci pouze pomocí zobrazení (buď vámi zadaného zobrazení, nebo výchozího zobrazení kolekce), mají všechny vazby na kolekce ukazatel aktuální položky. Při vytváření vazby na zobrazení určuje znak lomítka („/“) v hodnotě Path aktuální položku zobrazení. V následujícím příkladu je kontext dat zobrazení kolekce. První řádek vytvoří vazbu na kolekci. Druhý řádek tvoří vazba na aktuální položku v kolekci. Třetí řádek je vazbou na vlastnost Description aktuální položky v kolekci.

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

Syntaxi lomítka a vlastnosti lze také poskládat tak, aby procházela hierarchii kolekcí. Následující příklad vytvoří vazbu na aktuální položku kolekce s názvem Offices, což je vlastnost aktuální položky kolekce zdrojů.

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

Ukazatel aktuální položky může být ovlivněn jakýmkoli řazením nebo filtrováním, které je v kolekci použito. Řazení zachová ukazatel aktuální položky na poslední vybrané položce, ale zobrazení kolekce se teď kolem něj znovu uspořádá. (Možná, že dříve byla vybraná položka na začátku seznamu, ale teď může být vybraná položka někde uprostřed.) Filtrování vybranou položku zachová, pokud tento výběr zůstane v zobrazení i po filtrování. V opačném případě je ukazatel aktuální položky nastavený na první položku filtrovaného zobrazení kolekce.

Scénář vazby seznam-podrobnosti

Pojem aktuální položky je užitečný nejen pro procházení položek v kolekci, ale také pro scénář vazby seznam-podrobnosti. Zamyslete se znovu nad uživatelským rozhraním aplikace v části Co je datová vazba. V této aplikaci výběr v rámci ListBox určuje obsah zobrazený v ContentControl. Jinak řečeno, když je vybraná položka ListBox, ContentControl zobrazí podrobnosti vybrané položky.

Scénář seznam-podrobnosti můžete implementovat jednoduše tak, že máte dva nebo více ovládacích prvků vázaných na stejné zobrazení. Následující příklad z ukázky datové vazby ukazuje kód ListBox a ContentControl v uživatelském rozhraní aplikace v části Co je datová vazba.

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

Všimněte si, že oba ovládací prvky jsou vázány na stejný zdroj, statický prostředek listingDataView (podívejte se na definici tohoto prostředku v části Postup vytvoření zobrazení). Tato vazba funguje, protože když je jeden objekt (v tomto případě ContentControl) vázán na zobrazení kolekce, automaticky je vázán na CurrentItem zobrazení. Objekty CollectionViewSource automaticky synchronizují měnu a výběr. Pokud ovládací prvek seznamu není vázán na CollectionViewSource objekt jako v tomto příkladu, budete muset nastavit jeho IsSynchronizedWithCurrentItem vlastnost tak, aby true tato funkce fungovala.

Další příklady najdete v tématu Vytvoření vazby ke kolekci a zobrazení informací na základě výběru a použití vzoru hlavních podrobností s hierarchickými daty.

Možná jste si všimli, že výše uvedený příklad používá šablonu. Ve skutečnosti by se data nezobrazovala tak, jak chceme, bez použití šablon (té, kterou explicitně používá ContentControl, a té, kterou implicitně používá ListBox). Šablonováním dat se budeme zabývat v další části.

Vytváření šablon dat

Bez použití šablon dat by uživatelské rozhraní aplikace v části Co je datová vazba vypadalo takto.

Data Binding Demo without Data Templates

Jak je znázorněno v příkladu v předchozí části, ovládací prvek ListBox i ContentControl jsou vázány na celý objekt kolekce (nebo konkrétněji na zobrazení objektu kolekce) objektů AuctionItem. Bez konkrétních pokynů k zobrazení shromažďování ListBox dat se zobrazí řetězcová reprezentace každého objektu v podkladové kolekci a ContentControl zobrazí řetězcovou reprezentaci objektu, ke kterém je vázán.

Aby aplikace tento problém vyřešila, definuje DataTemplates. Jak je znázorněno v příkladu v předchozí části, ContentControl explicitně používá šablonu dat detailsProductListingTemplate. Ovládací prvek ListBox implicitně používá následující šablonu dat při zobrazování objektů AuctionItem v kolekci.

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

Výsledkem použití těchto dvou DataTemplates je uživatelské rozhraní zobrazené v části Co je datová vazba. Jak vidíte na tomto snímku obrazovky, kromě toho, že vám umožní umístit data do ovládacích prvků, vám DataTemplates umožní definovat působivé vizuály pro vaše data. Například DataTrigger se ve výše uvedeném DataTemplate používají, aby se AuctionItem s hodnotou SpecialFeaturesHighLight zobrazovaly s oranžovým ohraničením a hvězdičkou.

Další informace o šablonách dat najdete v přehledu šablon dat.

Ověření dat

Většina aplikací, které přebírají vstup uživatele, musí mít logiku ověření, aby se zajistilo, že uživatel zadal očekávané informace. Kontroly ověření mohou být založené na typu, rozsahu, formátu nebo jiných požadavcích specifických pro aplikaci. Tato část popisuje, jak funguje ověřování dat v WPF.

Přidružení pravidel ověřování k vazbě

Model datové vazby WPF umožňuje přidružit ValidationRules k objektu Binding. Následující příklad vytvoří vazbu TextBox na vlastnost s názvem StartPrice a přidá objekt ExceptionValidationRule do vlastnosti 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>

Objekt ValidationRule kontroluje, jestli je hodnota vlastnosti platná. WPF má dva typy integrovaných objektů ValidationRule:

Vlastní ověřovací pravidlo můžete také vytvořit odvozením ze třídy ValidationRule a implementací metody Validate. Následující příklad ukazuje pravidlo používané přidáním výpisu produktů „Počáteční datum“ TextBox z části Co je datová vazba.

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

StartDateEntryFormTextBox používá toto FutureDateRule, jak je vidět v následujícím příkladu.

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

Vzhledem k tomu, že hodnota UpdateSourceTrigger je PropertyChanged, modul vazeb aktualizuje hodnotu zdroje při každém stisknutí kláves, což znamená, že při každém stisknutí kláves také kontroluje každé pravidlo v kolekci ValidationRules. Tento postup si probereme později v části Proces ověřování.

Poskytnutí vizuální zpětné vazby

Pokud uživatel zadá neplatnou hodnotu, můžete chtít poskytnout zpětnou vazbu týkající se chyby v uživatelském rozhraní aplikace. Jedním ze způsobů, jak takovou zpětnou vazbu poskytnout, je nastavit přidruženou vlastnost Validation.ErrorTemplate na vlastní ControlTemplate. Jak je znázorněno v předchozí dílčí části, StartDateEntryFormTextBox používá ErrorTemplate s názvem validationTemplate. Následující příklad ukazuje definici validationTemplate.

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

Element AdornedElementPlaceholder určuje, kam má být označený ovládací prvek umístěn.

Kromě toho můžete také použít ToolTip k zobrazení chybové zprávy. StartDateEntryForm a StartPriceEntryFormTextBox používají styl textStyleTextBox, který vytvoří ToolTip zobrazující chybovou zprávu. Následující příklad ukazuje definici textStyleTextBox. Přidružená vlastnost Validation.HasError je true, když je jedna nebo více vazeb na vlastnosti vázaného prvku chybná.

<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 RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>

Při použití vlastního ErrorTemplate prvku a ToolTipformuláře StartDateEntryFormTextBox vypadá následující, pokud dojde k chybě ověření.

Data binding validation error

Binding Pokud máte přidružená ověřovací pravidla, ale neurčíte ErrorTemplate ho v vázaném ovládacím prvku, použije se výchozí nastaveníErrorTemplate, které uživatele upozorní, když dojde k chybě ověření. Výchozí ErrorTemplate je šablona ovládacího prvku, která definuje červené ohraničení ve vrstvě doplňku pro úpravy. Ve výchozím nastavení ErrorTemplate a ToolTipuživatelské rozhraní StartPriceEntryFormTextBox vypadá jako následující, pokud dojde k chybě ověření.

Data binding validation error default

Příklad poskytnutí logiky pro ověření všech ovládacích prvků v dialogovém okně najdete v části Vlastní dialogová okna v Přehledu dialogových oken.

Proces ověření

K ověření obvykle dochází, když je hodnota cíle přenesena do vlastnosti zdroje vazby. K tomuto přenosu dochází u vazeb TwoWay a OneWayToSource. Zopakujme si, že to, co způsobuje aktualizaci zdroje, závisí na hodnotě vlastnosti UpdateSourceTrigger, jak je popsáno v části Co aktivuje aktualizace zdroje.

Následující položky popisují proces ověření. Pokud kdykoli během tohoto procesu dojde k chybě ověření nebo jinému typu chyby, proces se zastaví:

  1. Modul vazeb zkontroluje, jestli jsou definovány nějaké vlastní objekty ValidationRule, jejichž ValidationStep je nastaven na RawProposedValue pro tuto Binding. V takovém případě volá metodu Validate pro každé ValidationRule, dokud u některého z nich nedojde k chybě nebo dokud všechny úspěšně neprojdou.

  2. Modul vazeb pak zavolá převaděč, pokud existuje.

  3. Pokud je převaděč úspěšný, modul vazeb zkontroluje, jestli jsou definovány nějaké vlastní objekty ValidationRule, jejichž ValidationStep je nastaven na ConvertedProposedValue pro tuto Binding. V takovém případě volá metodu Validate pro každé ValidationRule, které má ValidationStep nastavený na ConvertedProposedValue, dokud u některého z nich nedojde k chybě nebo dokud všechny úspěšně neprojdou.

  4. Modul vazeb nastaví vlastnost zdroje.

  5. Modul vazeb zkontroluje, jestli jsou definovány nějaké vlastní objekty ValidationRule, jejichž ValidationStep je nastaven na UpdatedValue pro tuto Binding. V takovém případě volá metodu Validate pro každé ValidationRule, které má ValidationStep nastavený na UpdatedValue, dokud u některého z nich nedojde k chybě nebo dokud všechny úspěšně neprojdou. Pokud je DataErrorValidationRule přidružené vazbě a jeho ValidationStep je nastavený na výchozí, UpdatedValue, bude se v tomto okamžiku kontrolovat DataErrorValidationRule. V tomto okamžiku se kontrolují všechny vazby, které mají ValidatesOnDataErrors nastavené na true.

  6. Modul vazeb zkontroluje, jestli jsou definovány nějaké vlastní objekty ValidationRule, jejichž ValidationStep je nastaven na CommittedValue pro tuto Binding. V takovém případě volá metodu Validate pro každé ValidationRule, které má ValidationStep nastavený na CommittedValue, dokud u některého z nich nedojde k chybě nebo dokud všechny úspěšně neprojdou.

ValidationRule Pokud se v průběhu tohoto procesu nepředá v žádném okamžiku, vytvoří modul vazby ValidationError objekt a přidá ho do Validation.Errors kolekce vázaného prvku. Dříve, než modul vazby spustí objekty ValidationRule v libovolném kroku, odebere všechny ValidationError přidané do přidružené vlastnosti Validation.Errors vázaného prvku během tohoto kroku. Pokud například ValidationRule, jehož ValidationStep je nastaven na UpdatedValue, selhalo, odebere modul vazeb před příštím procesem ověření tuto ValidationError bezprostředně před voláním libovolného ValidationRule, které má ValidationStep nastavený na UpdatedValue.

Pokud Validation.Errors není prázdná, připojená Validation.HasError vlastnost prvku je nastavena na true. Pokud je vlastnost NotifyOnValidationError objektu Binding nastavená na true, pak modul vazby vyvolá u elementu přidruženou událost Validation.Error.

Všimněte si také, že platný přenos hodnot v obou směrech (cíl na zdroj nebo zdroj na cíl) vymaže přidruženou vlastnost Validation.Errors.

Pokud je ExceptionValidationRule k vazbě přidružena nebo pokud ValidatesOnExceptions je vlastnost nastavena true a je vyvolán výjimka, když vazební modul nastaví zdroj, modul vazby zkontroluje, zda existuje UpdateSourceExceptionFilter. Máte možnost použít UpdateSourceExceptionFilter zpětné volání k poskytnutí vlastní obslužné rutiny pro zpracování výjimek. UpdateSourceExceptionFilter Pokud není zadán v vazbu Bindingmodul vytvoří ValidationError s výjimkou a přidá ho do Validation.Errors kolekce vázaného prvku.

Mechanismus ladění

Přidruženou vlastnost PresentationTraceSources.TraceLevel můžete nastavit u objektu souvisejícího s vazbou, abyste získali informace o stavu konkrétní vazby.

Viz také