Sdílet prostřednictvím


Hloubková datová vazba

Důležitá rozhraní API

Poznámka:

Toto téma podrobně popisuje funkce datových vazeb. Stručný praktický úvod najdete v přehledu datových vazeb.

Toto téma se týká datových vazeb pro rozhraní API, která se nacházejí v oboru názvů Windows.UI.Xaml.Data.

Datová vazba je způsob, jak může uživatelské rozhraní vaší aplikace zobrazovat data a volitelně zůstávat synchronizované s těmito daty. Datová vazba umožňuje oddělit obavy z dat od problému uživatelského rozhraní a výsledkem je jednodušší koncepční model a lepší čitelnost, testovatelnost a udržovatelnost aplikace.

Datovou vazbu můžete použít k jednoduchému zobrazení hodnot ze zdroje dat při prvním zobrazení uživatelského rozhraní, ale nereagování na změny v těchto hodnotách. Jedná se o režim vazby, který se nazývá jednorázově, a funguje dobře pro hodnotu, která se během běhu nemění. Alternativně můžete zvolit, že chcete hodnoty sledovat a aktualizovat uživatelské rozhraní při změně. Tento režim se nazývá jednosměrně a funguje dobře pro data jen pro čtení. Nakonec se můžete rozhodnout sledovat i aktualizovat, aby změny, které uživatel provede u hodnot v uživatelském rozhraní, byly automaticky vloženy zpět do zdroje dat. Tento režim se nazývá obousměrně a funguje dobře pro data pro čtení i zápis. Tady je několik příkladů.

  • Jednorázový režim můžete použít k vytvoření vazby obrázku na fotku aktuálního uživatele.
  • Jednosměrný režim můžete použít k vytvoření vazby ListView na kolekci článků zpráv v reálném čase seskupených podle oddílu novin.
  • Pomocí obousměrného režimu můžete vytvořit vazbu textového pole na jméno zákazníka ve formuláři.

Nezávisle na režimu existují dva druhy vazeb a oba jsou obvykle deklarovány v kódu uživatelského rozhraní. Můžete použít buď rozšíření značek {x:Bind} , nebo rozšíření značek {Binding}. A dokonce můžete použít kombinaci těchto dvou ve stejné aplikaci – dokonce i na stejném prvku uživatelského rozhraní. {x:Bind} je pro Windows 10 nový a má lepší výkon. Všechny podrobnosti popsané v tomto tématu platí pro oba druhy vazeb, pokud explicitně neřekneme jinak.

Ukázkové aplikace, které demonstrují {x:Bind}

Ukázkové aplikace, které demonstrují {Binding}

Každá vazba zahrnuje tyto části.

  • Zdroj vazby. Toto je zdroj dat pro vazbu a může to být instance jakékoli třídy, která má členy, jejichž hodnoty chcete zobrazit v uživatelském rozhraní.
  • Cíl vazby. Toto je DependencyPropertyFrameworkElement v uživatelském rozhraní, který zobrazuje data.
  • Objekt vazby. Toto je část, která přenáší hodnoty dat ze zdroje do cíle a volitelně z cíle zpět do zdroje. Objekt vazby se vytvoří v době načítání XAML z rozšíření značek {x:Bind} nebo {Binding} .

V následujících částech se podrobněji podíváme na zdroj vazby, cíl vazby a objekt vazby. A propojíme oddíly společně s příkladem vazby obsahu tlačítka na řetězcovou vlastnost s názvem NextButtonText, která patří do třídy s názvem HostViewModel.

Zdroj vazby

Tady je velmi základní implementace třídy, kterou bychom mohli použít jako zdroj vazby.

Pokud používáte C++/WinRT, přidejte do projektu nové položky midl File (.idl), které jsou uvedené v příkladu kódu C++/WinRT níže. Nahraďte obsah těchto nových souborů kódem MIDL 3.0 zobrazeným ve výpisu, sestavte projekt pro vygenerování HostViewModel.h a .cpppak přidejte kód do vygenerovaných souborů tak, aby odpovídal výpisu. Další informace o vygenerovaných souborech a o tom, jak je zkopírovat do projektu, najdete v tématu Ovládací prvky XAML, vazba na vlastnost C++/WinRT.

public class HostViewModel
{
    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText { get; set; }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Implement the constructor like this, and add this field:
...
HostViewModel() : m_nextButtonText{ L"Next" } {}
...
private:
    std::wstring m_nextButtonText;
...

// HostViewModel.cpp
// Implement like this:
...
hstring HostViewModel::NextButtonText()
{
    return hstring{ m_nextButtonText };
}

void HostViewModel::NextButtonText(hstring const& value)
{
    m_nextButtonText = value;
}
...

Tato implementace HostViewModel a jeho vlastnost NextButtonText, jsou vhodné pouze pro jednorázové vazby. Jednosměrné a obousměrné vazby jsou ale velmi běžné a v těchto typech vazeb se uživatelské rozhraní automaticky aktualizuje v reakci na změny datových hodnot zdroje vazby. Aby tyto druhy vazeb fungovaly správně, musíte zdroj vazby nastavit jako pozorovatelný pro objekt vazby. Pokud tedy v našem příkladu chceme jednosměrnou nebo obousměrnou vazbu na Vlastnost NextButtonText , pak všechny změny, ke kterým dochází za běhu, na hodnotu této vlastnosti musí být pozorovatelné pro objekt vazby.

Jedním ze způsobů, jak to udělat, je odvodit třídu, která představuje váš zdroj vazby z DependencyObject, a zveřejnit hodnotu dat prostřednictvím DependencyProperty. To je způsob, jakým se FrameworkElement stává pozorovatelným. FrameworkElements jsou dobré vazby zdroje přímo z krabice.

Jednodušší způsob, jak vytvořit pozorovatelnou třídu a nezbytnou pro třídy, které již mají základní třídu, je implementovat System.ComponentModel.INotifyPropertyChanged. To skutečně zahrnuje implementaci jedné události s názvem PropertyChanged. Příklad použití HostViewModel je níže.

...
using System.ComponentModel;
using System.Runtime.CompilerServices;
...
public class HostViewModel : INotifyPropertyChanged
{
    private string nextButtonText;

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set
        {
            this.nextButtonText = value;
            this.OnPropertyChanged();
        }
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // Raise the PropertyChanged event, passing the name of the property whose value has changed.
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
// HostViewModel.idl
namespace DataBindingInDepth
{
    runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        HostViewModel();
        String NextButtonText;
    }
}

// HostViewModel.h
// Add this field:
...
    winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
    void PropertyChanged(winrt::event_token const& token) noexcept;

private:
    winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
...

// HostViewModel.cpp
// Implement like this:
...
void HostViewModel::NextButtonText(hstring const& value)
{
    if (m_nextButtonText != value)
    {
        m_nextButtonText = value;
        m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"NextButtonText" });
    }
}

winrt::event_token HostViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
    return m_propertyChanged.add(handler);
}

void HostViewModel::PropertyChanged(winrt::event_token const& token) noexcept
{
    m_propertyChanged.remove(token);
}
...

Vlastnost NextButtonText je nyní pozorovatelná. Když vytvoříte jednosměrnou nebo obousměrnou vazbu na tuto vlastnost (ukážeme si, jak později), výsledný objekt vazby se přihlásí k odběru události PropertyChanged . Při vyvolání události obslužná rutina objektu vazby obdrží argument obsahující název vlastnosti, která se změnila. Takto objekt vazby ví, která hodnota vlastnosti se má přejít a znovu číst.

Abyste nemuseli implementovat vzor uvedený výše několikrát, pokud používáte jazyk C#, můžete jednoduše odvodit základní třídu BindableBase , kterou najdete v ukázce QuizGame (ve složce Common). Tady je příklad, jak to vypadá.

public class HostViewModel : BindableBase
{
    private string nextButtonText;

    public HostViewModel()
    {
        this.NextButtonText = "Next";
    }

    public string NextButtonText
    {
        get { return this.nextButtonText; }
        set { this.SetProperty(ref this.nextButtonText, value); }
    }
}
// Your BindableBase base class should itself derive from Windows::UI::Xaml::DependencyObject. Then, in HostViewModel.idl, derive from BindableBase instead of implementing INotifyPropertyChanged.

Poznámka:

Pro C++/WinRT je každá třída modulu runtime, kterou deklarujete ve své aplikaci, která je odvozena ze základní třídy, známá jako kompozable třída. A existují omezení ohledně kompozovatelných tříd. Aby aplikace předala testy sady Windows App Certification Kit používané sadou Visual Studio a Microsoft Store k ověření odeslání (a proto aby aplikace úspěšně ingestována do Microsoft Storu), musí být kompozovatelná třída nakonec odvozena ze základní třídy Windows. To znamená, že třída na velmi kořenovém adresáři hierarchie dědičnosti musí být typ pocházející z oboru názvů Windows.* Pokud potřebujete odvodit třídu modulu runtime ze základní třídy , například k implementaci BindableBase třídy pro všechny modely zobrazení, ze kterých se mají odvozovat, můžete odvození z Windows.UI.Xaml.DependencyObject.

Vyvolání události PropertyChanged s argumentem String.Empty nebo null označuje, že všechny vlastnosti neindexeru objektu by měly být znovu přečteny. Událost můžete vyvolat, aby bylo možné indikovat, že se vlastnosti indexeru objektu změnily pomocí argumentu Item[indexer] pro konkrétní indexery (kde indexer je hodnota indexu) nebo hodnoty Item[] pro všechny indexery.

Zdroj vazby lze považovat za jeden objekt, jehož vlastnosti obsahují data, nebo jako kolekci objektů. V kódu jazyka C# a Visual Basic můžete jednorázově vytvořit vazbu na objekt, který implementuje List(Of T), aby se zobrazila kolekce, která se nemění za běhu. U pozorovatelné kolekce (pozorující, kdy jsou položky přidány do kolekce a odebrány), jednosměrná vazba na ObservableCollection(Of T) místo toho. V kódu C++/CX můžete vytvořit vazbu na vektor<T> pro pozorovatelné i pozorovatelné kolekce a jazyk C++/WinRT má své vlastní typy. Pokud chcete vytvořit vazbu s vlastními třídami kolekce, postupujte podle pokynů v následující tabulce.

Scenario C# a VB (CLR) C++/WinRT C++/CX
Vytvoření vazby k objektu Může to být libovolný objekt. Může to být libovolný objekt. Objekt musí mít BindableAttribute nebo implementovat ICustomPropertyProvider.
Umožňuje získat oznámení o změnách vlastností z vázaného objektu. Objekt musí implementovat INotifyPropertyChanged. Objekt musí implementovat INotifyPropertyChanged. Objekt musí implementovat INotifyPropertyChanged.
Vytvoření vazby k kolekci List(Of T) IVectorIInspectable nebo IBindableObservableVector. Podívejte se na ovládací prvky položek XAML; vytvořte vazbu na kolekci C++/WinRT a kolekce pomocí C++/WinRT. Vektor<T>
Získejte oznámení o změnách kolekcí z vázané kolekce. ObservableCollection(Of T) IObservableVectorIInspectable. Například winrt::single_threaded_observable_vector<T>. IObservableVector<T>. Vektor<T> implementuje toto rozhraní.
Implementujte kolekci, která podporuje vazbu. Extend List(Of T) nebo implementujte IList, IList(Of Object), IEnumerable nebo IEnumerable(Of Object). Vazba na obecný IList(Of T) a IEnumerable(Of T) není podporována. Implementujte IVectorIInspectable. Podívejte se na ovládací prvky položek XAML; vytvořte vazbu na kolekci C++/WinRT a kolekce pomocí C++/WinRT. Implementace IBindableVector, IBindableIterable, IVector<Object^>, IIterable<Object^>, IVector<IInspectable*>, nebo IIterable<IInspectable*>. Vazba na obecný IVector<T> a IIterable<T> není podporována.
Implementujte kolekci, která podporuje oznámení o změnách kolekce. Extend ObservableCollection(Of T) nebo implementujte (ne generické) IList a INotifyCollectionChanged. Implementace IObservableVectorIInspectable nebo IBindableObservableVector. Implementujte IBindableVector a IBindableObservableVector.
Implementujte kolekci, která podporuje přírůstkové načítání. Extend ObservableCollection(Of T) nebo implementujte (ne generické) IList a INotifyCollectionChanged. Kromě toho implementujte ISupportIncrementalLoading. Implementace IObservableVectorIInspectable nebo IBindableObservableVector. Kromě toho implementujte ISupportIncrementalLoading. Implementujte IBindableVector, IBindableObservableVector a ISupportIncrementalLoading.

Ovládací prvky seznamu můžete svázat s libovolnými velkými zdroji dat a dosáhnout vysokého výkonu pomocí přírůstkového načítání. Můžete například vytvořit vazbu ovládacích prvků seznamu na výsledky dotazů obrázků Bingu, aniž byste museli načíst všechny výsledky najednou. Místo toho načtete jenom některé výsledky okamžitě a podle potřeby načtete další výsledky. Pokud chcete podporovat přírůstkové načítání, musíte implementovat ISupportIncrementalLoading ve zdroji dat, který podporuje oznámení o změnách kolekce. Když modul datových vazeb požaduje více dat, musí zdroj dat provést příslušné požadavky, integrovat výsledky a pak odeslat příslušná oznámení, aby bylo možné aktualizovat uživatelské rozhraní.

Cíl vazby

V následujících dvou příkladech je Vlastnost Button.Content cílovou vazbou a její hodnota je nastavena na rozšíření značek, které deklaruje objekt vazby. Nejprve se zobrazí {x:Bind} a pak {Binding}. Deklarování vazeb v kódu je běžný případ (je to pohodlné, čitelné a použitelné). Pokud ale potřebujete, můžete se vyhnout vytváření revizí a imperativních (programových) instancí třídy Binding .

<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />

Pokud používáte rozšíření komponent C++/WinRT nebo Visual C++ (C++/CX), budete muset přidat atribut BindableAttribute do jakékoli třídy modulu runtime, se kterou chcete použít rozšíření značek {Binding} .

Důležité

Pokud používáte C++/WinRT, je atribut BindableAttribute dostupný, pokud jste nainstalovali sadu Windows SDK verze 10.0.17763.0 (Windows 10, verze 1809) nebo novější. Bez tohoto atributu budete muset implementovat rozhraní ICustomPropertyProvider a ICustomProperty , aby bylo možné použít rozšíření značek {Binding} .

Objekt vazby deklarovaný pomocí {x:Bind}

Před vytvořením kódu {x:Bind} musíme udělat jeden krok. Musíme zveřejnit zdrojovou třídu vazby z třídy, která představuje naši stránku revize. Děláme to přidáním vlastnosti (typu HostViewModel v tomto případě) do naší Třídy stránky MainPage .

namespace DataBindingInDepth
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.ViewModel = new HostViewModel();
        }
    
        public HostViewModel ViewModel { get; set; }
    }
}
// MainPage.idl
import "HostViewModel.idl";

namespace DataBindingInDepth
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        HostViewModel ViewModel{ get; };
    }
}

// MainPage.h
// Include a header, and add this field:
...
#include "HostViewModel.h"
...
    DataBindingInDepth::HostViewModel ViewModel();

private:
    DataBindingInDepth::HostViewModel m_viewModel{ nullptr };
...

// MainPage.cpp
// Implement like this:
...
MainPage::MainPage()
{
    InitializeComponent();

}

DataBindingInDepth::HostViewModel MainPage::ViewModel()
{
    return m_viewModel;
}
...

To je hotové, teď se můžeme blíže podívat na značku, která deklaruje objekt vazby. Následující příklad používá stejný cíl vazby Button.Content , který jsme použili dříve v části Cíl vazby a ukazuje, že je svázán s HostViewModel.NextButtonText vlastnost.

<!-- MainPage.xaml -->
<Page x:Class="DataBindingInDepth.Mainpage" ... >
    <Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Page>

Všimněte si hodnoty, kterou pro cestu zadáváme. Tato hodnota je interpretována v kontextu samotné stránky, a v tomto případě cesta začíná odkazem na ViewModel vlastnost, kterou jsme právě přidali na stránku MainPage . Tato vlastnost vrátí HostViewModel instance, a proto můžeme do toho objektu získat přístup HostViewModel.NextButtonText vlastnost. A určíme režim, který přepíše výchozí hodnotu {x:Bind} jednorázového nastavení.

Vlastnost Path podporuje řadu možností syntaxe pro vazbu na vnořené vlastnosti, připojené vlastnosti a celočíselné a řetězcové indexery. Další informace najdete v tématu Syntaxe cesty vlastností. Vazba na řetězcové indexery poskytuje účinek vazby na dynamické vlastnosti bez nutnosti implementovat ICustomPropertyProvider. Další nastavení najdete v tématu {x:Bind} rozšíření značek.

Chcete-li ilustrovat, že HostViewModel.NextButtonText vlastnost je skutečně pozorovatelná, přidejte obslužnou rutinu Události Click na tlačítko a aktualizujte hodnotu HostViewModel.NextButtonText. Sestavte, spusťte a klikněte na tlačítko a zobrazte hodnotu aktualizace obsahu tlačítka.

// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.ViewModel.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ViewModel().NextButtonText(L"Updated Next button text");
}

Poznámka:

Změny TextBox.Text se posílají do obousměrného vázaného zdroje, když TextBox ztratí fokus, a ne po každém stisknutí klávesy uživatele.

DataTemplate a x:DataType

Uvnitř objektu DataTemplate (bez ohledu na to, jestli se používá jako šablona položky, šablona obsahu nebo šablona záhlaví), hodnota Path není interpretována v kontextu stránky, ale v kontextu objektu dat, který se šablonuje. Při použití {x:Bind} v šabloně dat, aby bylo možné jeho vazby ověřit (a efektivní kód vygenerovat pro ně) v době kompilace, dataTemplate musí deklarovat typ jeho datového objektu pomocí x:DataType. Níže uvedený příklad lze použít jako ItemTemplate ovládacího prvku items vázaného na kolekci SampleDataGroup objektů.

<DataTemplate x:Key="SimpleItemTemplate" x:DataType="data:SampleDataGroup">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{x:Bind Title}"/>
      <TextBlock Text="{x:Bind Description}"/>
    </StackPanel>
  </DataTemplate>

Slabě zadané objekty v cestě

Představte si například, že máte typ SampleDataGroup, který implementuje řetězcovou vlastnost s názvem Title. A máte vlastnost MainPage.SampleDataGroupAsObject, která je typu objekt, ale který ve skutečnosti vrací instanci SampleDataGroup. Výsledkem vazby <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> bude chyba kompilace, protože vlastnost Title nebyla nalezena u objektu typu. Nápravou je přidat přetypování do syntaxe cesty takto: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Tady je další příklad, kde element je deklarován jako objekt, ale ve skutečnosti je TextBlock: <TextBlock Text="{x:Bind Element.Text}"/>. A přetypování vyřeší problém: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.

Pokud se data načítají asynchronně

Kód pro podporu {x:Bind} se generuje v době kompilace v částečných třídách pro vaše stránky. Tyto soubory najdete ve složce obj s názvy jako (pro C#). <view name>.g.cs Vygenerovaný kód obsahuje obslužnou rutinu události Načítání stránky a tato obslužná rutina volá metodu Initialize ve vygenerované třídě, která představuje vazby vaší stránky. Inicializace volání aktualizace začít přesouvat data mezi zdrojem vazby a cílem. Načítání se vyvolá těsně před předáním první míry stránky nebo uživatelského ovládacího prvku. Takže pokud jsou data načtena asynchronně, nemusí být připravena při inicializaci je volána. Takže po načtení dat můžete vynutit jednorázové vazby inicializovat voláním this.Bindings.Update();. Pokud potřebujete jenom jednorázové vazby pro asynchronně načtená data, je mnohem levnější je inicializovat tímto způsobem, než je mít jednosměrné vazby a naslouchat změnám. Pokud vaše data neprocházejí jemně odstupňovanými změnami a pokud se pravděpodobně aktualizují jako součást konkrétní akce, můžete vytvořit vazby jednorázově a kdykoli vynutit ruční aktualizaci voláním aktualizace.

Poznámka:

{x:Bind} není vhodný pro scénáře s pozdní vazbou, jako je například navigace ve struktuře slovníku objektu JSON ani psaní kachny. "Duck typeing" je slabá forma psaní na základě lexikálních shod na názvech vlastností (stejně jako "pokud jde, plave a kurvy jako kachna, pak je to kachna"). Při psaní kachny by vazba na vlastnost Age byla stejně spokojena s objektem Person nebo Wine (za předpokladu, že tyto typy měly vlastnost Age ). Pro tyto scénáře použijte rozšíření značek {Binding} .

Objekt vazby deklarovaný pomocí {Binding}

Pokud používáte rozšíření komponent C++/WinRT nebo Visual C++ (C++/CX), budete muset k použití rozšíření značek {Binding} přidat atribut BindableAttribute do jakékoli třídy modulu runtime, se kterou chcete vytvořit vazbu. Pokud chcete použít {x:Bind}, tento atribut nepotřebujete.

// HostViewModel.idl
// Add this attribute:
[Windows.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
...

Důležité

Pokud používáte C++/WinRT, je atribut BindableAttribute dostupný, pokud jste nainstalovali sadu Windows SDK verze 10.0.17763.0 (Windows 10, verze 1809) nebo novější. Bez tohoto atributu budete muset implementovat rozhraní ICustomPropertyProvider a ICustomProperty , aby bylo možné použít rozšíření značek {Binding} .

{Binding} ve výchozím nastavení předpokládá, že jste vázáni na Objekt DataContext stránky revizí. Proto nastavíme DataContext naší stránky na instanci naší třídy zdroje vazby (v tomto případě typu HostViewModel ). Následující příklad ukazuje kód, který deklaruje objekt vazby. Používáme stejný cíl vazby Button.Content , který jsme dříve použili v části Cíl vazby, a vytvoříme vazbu na HostViewModel.NextButtonText vlastnost.

<Page xmlns:viewmodel="using:DataBindingInDepth" ... >
    <Page.DataContext>
        <viewmodel:HostViewModel x:Name="viewModelInDataContext"/>
    </Page.DataContext>
    ...
    <Button Content="{Binding Path=NextButtonText}" ... />
</Page>
// MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    this.viewModelInDataContext.NextButtonText = "Updated Next button text";
}
// MainPage.cpp
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    viewModelInDataContext().NextButtonText(L"Updated Next button text");
}

Všimněte si hodnoty, kterou pro cestu zadáváme. Tato hodnota je interpretována v kontextu DataContext stránky, který je v tomto příkladu nastaven na instanci HostViewModel. Cesta odkazuje Na HostViewModel.NextButtonText vlastnost. Režim můžeme vynechat, protože výchozí nastavení {Binding} jednosměrného způsobu funguje tady.

Výchozí hodnota DataContext prvku uživatelského rozhraní je zděděná hodnota nadřazeného prvku. Můžete samozřejmě toto výchozí nastavení přepsat nastavením DataContext explicitně, což je zase zděděno podřízenými položkami ve výchozím nastavení. Nastavení DataContext explicitně u elementu je užitečné, pokud chcete mít více vazeb, které používají stejný zdroj.

Objekt vazby má Source vlastnost, která ve výchozím nastavení DataContext prvku uživatelského rozhraní, na kterém je vazba deklarována. Toto výchozí nastavení můžete přepsat nastavením Source, RelativeSource nebo ElementName explicitně u vazby (podrobnosti najdete v části {Binding} ).

Uvnitř DataTemplate se DataContext automaticky nastaví na objekt dat, který je šablonován. Níže uvedený příklad lze použít jako ItemTemplate ovládacího prvku items vázaného na kolekci libovolného typu, který má vlastnosti řetězce s názvem Název a Popis.

<DataTemplate x:Key="SimpleItemTemplate">
    <StackPanel Orientation="Vertical" Height="50">
      <TextBlock Text="{Binding Title}"/>
      <TextBlock Text="{Binding Description"/>
    </StackPanel>
  </DataTemplate>

Poznámka:

Ve výchozím nastavení se změny TextBox.Text posílají do obousměrného vázaného zdroje, když TextBox ztratí fokus. Chcete-li způsobit odeslání změn po každém stisknutí klávesy uživatele, nastavte UpdateSourceTrigger na PropertyChanged vazby v revizí. Můžete také zcela převzít kontrolu nad tím, kdy se změny odešlou do zdroje nastavením UpdateSourceTrigger na Explicit. Potom zpracujete události v textovém poli (obvykle TextBox.TextChanged), volání GetBindingExpression v cíli získat BindingExpression objektu a nakonec volat BindingExpression.UpdateSource programově aktualizovat zdroj dat.

Vlastnost Path podporuje řadu možností syntaxe pro vazbu na vnořené vlastnosti, připojené vlastnosti a celočíselné a řetězcové indexery. Další informace najdete v tématu Syntaxe cesty vlastností. Vazba na řetězcové indexery poskytuje účinek vazby na dynamické vlastnosti bez nutnosti implementovat ICustomPropertyProvider. Vlastnost ElementName je užitečná pro vazby element-to-element. Vlastnost RelativeSource má několik použití, z nichž jeden je jako výkonnější alternativa k vazbě šablony uvnitř ControlTemplate. Další nastavení najdete v tématu {Binding} rozšíření značek a třídy Binding .

Co když zdroj a cíl nejsou stejného typu?

Pokud chcete řídit viditelnost prvku uživatelského rozhraní na základě hodnoty logické vlastnosti nebo pokud chcete vykreslit prvek uživatelského rozhraní barvou, která je funkcí oblasti nebo trendu číselné hodnoty, nebo pokud chcete zobrazit hodnotu data a času ve vlastnosti prvku uživatelského rozhraní, která očekává řetězec, pak budete muset převést hodnoty z jednoho typu na jiný. Existují případy, kdy správné řešení je zveřejnit další vlastnost správného typu ze zdrojové třídy vazby a ponechat logiku převodu zapouzdřenou a testovatelnou tam. To ale není flexibilní ani škálovatelné, pokud máte velká čísla nebo velké kombinace zdrojových a cílových vlastností. V takovém případě máte několik možností:

  • Pokud používáte {x:Bind}, můžete svázat přímo s funkcí a provést tento převod.
  • Nebo můžete zadat převaděč hodnot, který je objekt navržený k provedení převodu.

Převaděče hodnot

Tady je převaděč hodnot vhodný pro jednorázovou nebo jednosměrnou vazbu, která převede hodnotu DateTime na řetězcovou hodnotu obsahující měsíc. Třída implementuje IValueConverter.

public class DateToStringConverter : IValueConverter
{
    // Define the Convert method to convert a DateTime value to 
    // a month string.
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        // value is the data from the source object.
        DateTime thisdate = (DateTime)value;
        int monthnum = thisdate.Month;
        string month;
        switch (monthnum)
        {
            case 1:
                month = "January";
                break;
            case 2:
                month = "February";
                break;
            default:
                month = "Month not found";
                break;
        }
        // Return the value to pass to the target.
        return month;
    }

    // ConvertBack is not implemented for a OneWay binding.
    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
// See the "Formatting or converting data values for display" section in the "Data binding overview" topic.

A tady je postup, jak tento převaděč hodnot v kódu objektu vazby.

<UserControl.Resources>
  <local:DateToStringConverter x:Key="Converter1"/>
</UserControl.Resources>
...
<TextBlock Grid.Column="0" 
  Text="{x:Bind ViewModel.Month, Converter={StaticResource Converter1}}"/>
<TextBlock Grid.Column="0" 
  Text="{Binding Month, Converter={StaticResource Converter1}}"/>

Modul vazeb volá metody Convert a ConvertBack , pokud je pro vazbu definován parametr Converter . Při předání dat ze zdroje volá modul vazeb převést a předá vrácená data cíli. Když jsou data předána z cíle (pro obousměrnou vazbu), modul vazeb volá ConvertBack a předává vrácená data do zdroje.

Převaděč má také volitelné parametry: ConverterLanguage, který umožňuje zadat jazyk, který se má použít v převodu, a ConverterParameter, který umožňuje předat parametr pro logiku převodu. Příklad, který používá parametr převaděče, viz IValueConverter.

Poznámka:

Pokud při převodu dojde k chybě, nevyvolejte výjimku. Místo toho vraťte DependencyProperty.UnsetValue, který zastaví přenos dat.

Chcete-li zobrazit výchozí hodnotu, která se má použít vždy, když zdroj vazby nelze přeložit, nastavte vlastnost FallbackValue u objektu vazby v kódu. To je užitečné pro zpracování chyb převodu a formátování. Je také užitečné svázat se zdrojovými vlastnostmi, které nemusí existovat u všech objektů v vázané kolekci heterogenních typů.

Pokud vytvoříte vazbu textového ovládacího prvku na hodnotu, která není řetězcem, modul datových vazeb převede hodnotu na řetězec. Pokud je hodnota referenční typ, modul datových vazeb načte řetězcovou hodnotu voláním ICustomPropertyProvider.GetStringRepresentation nebo IStringable.ToString pokud je k dispozici, a jinak zavolá Object.ToString. Všimněte si však, že vazební modul bude ignorovat jakoukoli implementaci ToString , která skryje implementaci základní třídy. Implementace podtřídy by místo toho měly přepsat základní třídu ToString metoda. Podobně v nativních jazycích se zdá, že všechny spravované objekty implementují ICustomPropertyProvider a IStringable. Nicméně všechny volání GetStringRepresentation a IStringable.ToString jsou směrovány na Object.ToString nebo přepsání této metody, a nikdy na novou ToString implementace, která skryje implementaci základní třídy.

Poznámka:

Od Windows 10 verze 1607 poskytuje architektura XAML integrovanou logickou hodnotu pro převaděč viditelnosti. Převaděč mapuje hodnotu true na hodnotu visible výčtu a false na Sbalené , takže můžete vytvořit vazbu Viditelnost vlastnost na logickou hodnotu bez vytvoření převaděče. Pokud chcete použít integrovaný převaděč, minimální cílová verze sady SDK vaší aplikace musí být 14393 nebo novější. Nemůžete ho použít, když vaše aplikace cílí na starší verze Windows 10. Další informace o cílových verzích najdete v tématu Adaptivní kód verze.

Vazba funkce v {x:Bind}

{x:Bind} umožňuje poslednímu kroku v cestě vazby funkci. To lze použít k provádění převodů a k provádění vazeb, které závisí na více než jedné vlastnosti. Viz funkce v x:Bind

Vazba elementu k elementu

Vlastnost jednoho elementu XAML lze svázat s vlastností jiného elementu XAML. Tady je příklad toho, jak vypadá v revizích.

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Důležité

Potřebný pracovní postup pro vazbu element-to-element pomocí jazyka C++/WinRT naleznete v tématu Vazby element-to-element.

Slovníky prostředků s {x:Bind}

Rozšíření značek {x:Bind} závisí na generování kódu, takže potřebuje soubor s kódem obsahující konstruktor, který volá InitializeComponent (k inicializaci generovaného kódu). Slovník prostředků znovu použijete tak, že vytvoříte instanci jeho typu (aby se volal InitializeComponent ) místo odkazování na jeho název souboru. Tady je příklad toho, co dělat, pokud máte existující slovník prostředků a chcete v něm použít {x:Bind}.

TemplatesResourceDictionary.xaml

<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

using Windows.UI.Xaml.Data;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
    }
}

MainPage.xaml

<Page x:Class="ExampleNamespace.MainPage"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Page.Resources>
        <ResourceDictionary>
            .... 
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>
</Page>

Kombinování {x:Bind} a {Binding} v opakovaně použitelném stylu

I když předchozí příklad ukázal použití {x:Bind} v objektech DataTemplates, můžete také vytvořit opakovaně použitelné styly, které kombinují rozšíření značek {x:Bind} i {Binding}. To je užitečné v případě, že chcete svázat některé vlastnosti se známými hodnotami kompilace pomocí {x:Bind} a dalších vlastností k hodnotám runtime DataContext pomocí {Binding}.

Tady je příklad, který ukazuje, jak vytvořit opakovaně použitelný styl tlačítka, který používá oba přístupy vazby:

TemplatesResourceDictionary.xaml

<ResourceDictionary
    x:Class="ExampleNamespace.TemplatesResourceDictionary"
    .....
    xmlns:examplenamespace="using:ExampleNamespace">
    
    <!-- DataTemplate using x:Bind -->
    <DataTemplate x:Key="EmployeeTemplate" x:DataType="examplenamespace:IEmployee">
        <Grid>
            <TextBlock Text="{x:Bind Name}"/>
        </Grid>
    </DataTemplate>
    
    <!-- Style that mixes x:Bind and Binding -->
    <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{Binding ButtonBackgroundBrush}"/>
        <Setter Property="Foreground" Value="{Binding ButtonForegroundBrush}"/>
        <Setter Property="FontSize" Value="16"/>
        <Setter Property="Margin" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="RootBorder"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            CornerRadius="4">
                        <StackPanel Orientation="Horizontal" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                            <!-- x:Bind to a static property or page-level property -->
                            <Ellipse Width="8" Height="8" 
                                     Fill="{x:Bind DefaultIndicatorBrush}" 
                                     Margin="0,0,8,0"/>
                            <!-- Binding to DataContext -->
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              Foreground="{TemplateBinding Foreground}"
                                              FontSize="{TemplateBinding FontSize}"/>
                        </StackPanel>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <VisualState.Setters>
                                        <!-- Binding to DataContext for hover color -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{Binding ButtonHoverBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <VisualState.Setters>
                                        <!-- x:Bind to a compile-time known resource -->
                                        <Setter Target="RootBorder.Background" 
                                                Value="{x:Bind DefaultPressedBrush}"/>
                                    </VisualState.Setters>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

TemplatesResourceDictionary.xaml.cs

using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
 
namespace ExampleNamespace
{
    public partial class TemplatesResourceDictionary
    {
        public TemplatesResourceDictionary()
        {
            InitializeComponent();
        }
        
        // Properties for x:Bind - these are compile-time bound
        public SolidColorBrush DefaultIndicatorBrush { get; } = 
            new SolidColorBrush(Colors.Green);
            
        public SolidColorBrush DefaultPressedBrush { get; } = 
            new SolidColorBrush(Colors.DarkGray);
    }
}

Použití v MainPage.xaml s modelem ViewModel, který poskytuje hodnoty modulu runtime:

<Page x:Class="ExampleNamespace.MainPage"
    ....
    xmlns:examplenamespace="using:ExampleNamespace">

    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <examplenamespace:TemplatesResourceDictionary/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Page.Resources>
    
    <Page.DataContext>
        <examplenamespace:ButtonThemeViewModel/>
    </Page.DataContext>

    <StackPanel Margin="20">
        <!-- This button uses the mixed binding style -->
        <Button Content="Save" Style="{StaticResource CustomButtonStyle}"/>
        <Button Content="Cancel" Style="{StaticResource CustomButtonStyle}"/>
    </StackPanel>
</Page>

ButtonThemeViewModel.cs (DataContext, který poskytuje hodnoty vazby modulu runtime):

using System.ComponentModel;
using Windows.UI;
using Windows.UI.Xaml.Media;

namespace ExampleNamespace
{
    public class ButtonThemeViewModel : INotifyPropertyChanged
    {
        private SolidColorBrush _buttonBackgroundBrush = new SolidColorBrush(Colors.LightBlue);
        private SolidColorBrush _buttonForegroundBrush = new SolidColorBrush(Colors.DarkBlue);
        private SolidColorBrush _buttonHoverBrush = new SolidColorBrush(Colors.LightCyan);

        public SolidColorBrush ButtonBackgroundBrush
        {
            get => _buttonBackgroundBrush;
            set
            {
                _buttonBackgroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonBackgroundBrush)));
            }
        }

        public SolidColorBrush ButtonForegroundBrush
        {
            get => _buttonForegroundBrush;
            set
            {
                _buttonForegroundBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonForegroundBrush)));
            }
        }

        public SolidColorBrush ButtonHoverBrush
        {
            get => _buttonHoverBrush;
            set
            {
                _buttonHoverBrush = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonHoverBrush)));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

V tomto příkladu:

  • {Binding} se používá pro vlastnosti, které závisí na objektu DataContext (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush).
  • {x:Bind} se používá pro vlastnosti, které jsou známé v čase kompilace a patří do samotného ResourceDictionaryu (DefaultIndicatorBrush, DefaultPressedBrush).
  • Styl je opakovaně použitelný a lze ho použít na libovolné tlačítko.
  • Motivy za běhu jsou možné prostřednictvím objektu DataContext a stále využívají výkon {x:Bind} pro statické prvky.

Vazby událostí a příkazy ICommand

{x:Bind} podporuje funkci označovanou jako vazba událostí. Pomocí této funkce můžete určit obslužnou rutinu události pomocí vazby, což je další možnost nad zpracováním událostí pomocí metody v souboru kódu. Řekněme, že máte vlastnost RootFrame třídy MainPage .

public sealed partial class MainPage : Page
{
    ...
    public Frame RootFrame { get { return Window.Current.Content as Frame; } }
}

Pak můžete vytvořit vazbu události Click tlačítka na metodu u Frame objektu vrácený RootFrame vlastnost takto. Všimněte si, že také vytvoříme vazbu isEnabled vlastnost tlačítka na jiný člen stejného Frame.

<AppBarButton Icon="Forward" IsCompact="True"
IsEnabled="{x:Bind RootFrame.CanGoForward, Mode=OneWay}"
Click="{x:Bind RootFrame.GoForward}"/>

Přetížené metody nelze použít ke zpracování události pomocí této techniky. Také, pokud metoda, která zpracovává událost má parametry, pak musí být všechny přiřaditelné z typů všech parametrů události, v uvedeném pořadí. V tomto případě Frame.GoForward není přetížen a nemá žádné parametry (ale přesto by byl platný i v případě, že by vzal dva parametry objektu ). Frame.GoBack je však přetížen, takže tuto metodu nemůžeme použít s touto technikou.

Technika vazby událostí je podobná implementaci a využívání příkazů (příkaz je vlastnost, která vrací objekt, který implementuje rozhraní ICommand ). S příkazy pracují {x:Bind} i {Binding} . Takže nemusíte implementovat vzor příkazů několikrát, můžete použít pomocnou třídu DelegateCommand , kterou najdete v ukázce KvízGame (ve složce Common).

Vazba na kolekci složek nebo souborů

Pomocí rozhraní API v oboru názvů Windows.Storage můžete načíst data složek a souborů. Různé metody GetFilesAsync, GetFoldersAsync a GetItemsAsync však nevrací hodnoty, které jsou vhodné pro vazby na ovládací prvky seznamu. Místo toho je nutné vytvořit vazbu na návratové hodnoty GetVirtualizedFilesVector, GetVirtualizedFoldersVector a GetVirtualizedItemsVector metody FileInformationFactory třídy. Následující příklad kódu z StorageDataSource a GetVirtualizedFilesVector ukázka ukazuje typický vzor použití. Nezapomeňte deklarovat funkci picturesLibrary v manifestu balíčku aplikace a potvrdit, že jsou obrázky ve složce knihovny Obrázky.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var library = Windows.Storage.KnownFolders.PicturesLibrary;
    var queryOptions = new Windows.Storage.Search.QueryOptions();
    queryOptions.FolderDepth = Windows.Storage.Search.FolderDepth.Deep;
    queryOptions.IndexerOption = Windows.Storage.Search.IndexerOption.UseIndexerWhenAvailable;

    var fileQuery = library.CreateFileQueryWithOptions(queryOptions);

    var fif = new Windows.Storage.BulkAccess.FileInformationFactory(
        fileQuery,
        Windows.Storage.FileProperties.ThumbnailMode.PicturesView,
        190,
        Windows.Storage.FileProperties.ThumbnailOptions.UseCurrentScale,
        false
        );

    var dataSource = fif.GetVirtualizedFilesVector();
    this.PicturesListView.ItemsSource = dataSource;
}

Tento přístup obvykle použijete k vytvoření zobrazení souborů a složek jen pro čtení. Můžete vytvořit obousměrné vazby na vlastnosti souboru a složky, například umožnit uživatelům hodnotit skladbu v hudebním zobrazení. Všechny změny však nejsou zachovány, dokud nezavoláte odpovídající metodu SavePropertiesAsync (například MusicProperties.SavePropertiesAsync). Změny byste měli potvrdit, když položka ztratí fokus, protože tím se aktivuje resetování výběru.

Všimněte si, že obousměrná vazba pomocí této techniky funguje pouze s indexovanými umístěními, jako je například Hudba. Můžete určit, zda je umístění indexováno voláním FolderInformation.GetIndexedStateAsync metoda.

Všimněte si také, že virtualizovaný vektor může vrátit hodnotu null pro některé položky předtím, než naplní jejich hodnotu. Před použitím hodnoty SelectedItem ovládacího prvku seznamu vázaného na virtualizovaný vektor byste například měli zkontrolovat hodnotu null nebo místo toho použít SelectedIndex.

Vazba na data seskupené podle klíče

Pokud vezmete plochou kolekci položek (například knihy reprezentované třídou BookSku ) a položky seskupíte pomocí společné vlastnosti jako klíče (například BookSku.AuthorName vlastnost), výsledek se nazývá seskupené data. Když data seskupíte, už se nejedná o plochou kolekci. Seskupené data jsou kolekce objektů skupiny, kde každý objekt skupiny obsahuje.

  • klíč a
  • kolekce položek, jejichž vlastnost odpovídá danému klíči.

Pokud chcete znovu vzít příklad knih, výsledkem seskupení knih podle jména autora je kolekce skupin jmen autorů, ve kterých má každá skupina

  • klíč, což je jméno autora a
  • kolekce BookSkus, jejíž Vlastnost AuthorName odpovídá klíči skupiny.

Obecně platí, že chcete-li zobrazit kolekci, vytvořte vazbu ItemsSource ovládacího prvku items (například ListView nebo GridView) přímo na vlastnost, která vrací kolekci. Pokud se jedná o plochou kolekci položek, nemusíte dělat nic zvláštního. Pokud se ale jedná o kolekci objektů skupiny (jak je to při vazbě k seskupeným datům), potřebujete služby zprostředkujícího objektu označovaného jako CollectionViewSource , který se nachází mezi ovládacím prostředkem položek a zdrojem vazby. Svážete CollectionViewSource s vlastností, která vrací seskupené data, a vytvoříte vazbu položky ovládacího prvku CollectionViewSource. Další přidaná hodnota CollectionViewSource je, že udržuje přehled o aktuální položce, takže můžete udržovat více než jeden ovládací prvek položky v synchronizaci tím, že je všechny vazby na stejný CollectionViewSource. K aktuální položce lze také přistupovat programově prostřednictvím ICollectionView.CurrentItem vlastnost objektu vrácené CollectionViewSource.View vlastnost.

Chcete-li aktivovat seskupovací zařízení CollectionViewSource, nastavte IsSourceGrouped na hodnotu true. To, zda také potřebujete nastavit vlastnost ItemsPath , závisí přesně na tom, jak vytvoříte objekty skupiny. Existují dva způsoby, jak vytvořit objekt skupiny: vzor "is-a-group" a vzor "has-a-group". V modelu "is-a-group" je objekt skupiny odvozen z typu kolekce (například List<T>), takže objekt skupiny je ve skutečnosti sám skupina položek. V tomto vzoru není nutné nastavit ItemsPath. V vzoru "has-a-group" má objekt skupiny jednu nebo více vlastností typu kolekce (například List<T>), takže skupina "má" skupinu položek ve formě vlastnosti (nebo několik skupin položek ve formě několika vlastností). Pomocí tohoto vzoru je nutné nastavit ItemsPath na název vlastnosti, která obsahuje skupinu položek.

Následující příklad znázorňuje vzor "has-a-group". Třída stránky má vlastnost s názvem ViewModel, která vrací instanci našeho modelu zobrazení. CollectionViewSource vytvoří vazbu na vlastnost Authors modelu zobrazení (Autoři je kolekce objektů skupiny) a také určuje, že se jedná o Vlastnost Author.BookSkus, která obsahuje seskupené položky. Nakonec je Objekt GridView vázán na CollectionViewSource a má definovaný styl skupiny, aby mohl vykreslit položky ve skupinách.

<Page.Resources>
    <CollectionViewSource
    x:Name="AuthorHasACollectionOfBookSku"
    Source="{x:Bind ViewModel.Authors}"
    IsSourceGrouped="true"
    ItemsPath="BookSkus"/>
</Page.Resources>
...
<GridView
ItemsSource="{x:Bind AuthorHasACollectionOfBookSku}" ...>
    <GridView.GroupStyle>
        <GroupStyle
            HeaderTemplate="{StaticResource AuthorGroupHeaderTemplateWide}" ... />
    </GridView.GroupStyle>
</GridView>

Model is-a-group můžete implementovat jedním ze dvou způsobů. Jedním ze způsobů je vytvoření vlastní třídy skupiny. Odvození třídy ze seznamu<T> (kde T je typ položek). Například: public class Author : List<BookSku>. Druhým způsobem je použití výrazu LINQ k dynamickému vytváření objektů skupiny (a třídy skupiny) z hodnot vlastností položek BookSku . Tento přístup je typický pro aplikaci, která přistupuje k datům z cloudové služby. Získáte flexibilitu při seskupování knih podle autora nebo žánru (například) bez nutnosti speciálních skupinových tříd, jako je Autor a Žánr.

Následující příklad znázorňuje vzor "is-a-group" pomocí LINQ. Tentokrát seskupíme knihy podle žánru, které se zobrazí s názvem žánru v záhlaví skupiny. To je označeno cestou vlastnosti "Klíč" v odkazu na hodnotu klíče skupiny.

using System.Linq;
...
private IOrderedEnumerable<IGrouping<string, BookSku>> genres;

public IOrderedEnumerable<IGrouping<string, BookSku>> Genres
{
    get
    {
        if (this.genres == null)
        {
            this.genres = from book in this.bookSkus
                          group book by book.genre into grp
                          orderby grp.Key
                          select grp;
        }
        return this.genres;
    }
}

Mějte na paměti, že při použití {x:Bind} s datovými šablonami musíme označit typ svázaný nastavením hodnoty x:DataType . Pokud je typ obecný, nemůžeme ho vyjádřit ve značkách, takže musíme místo toho použít {Binding} v šabloně záhlaví stylu skupiny.

    <Grid.Resources>
        <CollectionViewSource x:Name="GenreIsACollectionOfBookSku"
        Source="{x:Bind Genres}"
        IsSourceGrouped="true"/>
    </Grid.Resources>
    <GridView ItemsSource="{x:Bind GenreIsACollectionOfBookSku}">
        <GridView.ItemTemplate x:DataType="local:BookTemplate">
            <DataTemplate>
                <TextBlock Text="{x:Bind Title}"/>
            </DataTemplate>
        </GridView.ItemTemplate>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Key}"/>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </GridView.GroupStyle>
    </GridView>

Ovládací prvek SémanticZoom je skvělý způsob, jak uživatelé zobrazit a procházet seskupovaná data. Ukázková aplikace Bookstore2 ukazuje, jak používat sémanticZoom. V této aplikaci můžete zobrazit seznam knih seskupených podle autora (přiblížení v zobrazení) nebo můžete oddálit a zobrazit seznam autorů přeskakování (oddálit zobrazení). Seznam skoků nabízí mnohem rychlejší navigaci než procházení seznamu knih. Přiblížení a oddálení zobrazení jsou ve skutečnosti Ovládací prvky ListView nebo GridView vázané na stejný CollectionViewSource.

Obrázek SémanticZoom

Při vytváření vazby k hierarchickým datům , jako jsou podkategorie v kategoriích, můžete zvolit zobrazení hierarchických úrovní v uživatelském rozhraní pomocí řady ovládacích prvků položek. Výběr v jednom ovládacím prvku položek určuje obsah následných položek. Seznamy můžete udržovat synchronizované vazbou každého seznamu na vlastní CollectionViewSource a vytvořit vazbu instance CollectionViewSource dohromady v řetězu. Tomu se říká zobrazení master/details (nebo list/details). Další informace najdete v tématu Vytvoření vazby k hierarchickým datům a vytvoření zobrazení předlohy a podrobností.

Diagnostika a ladění problémů s datovými vazbami

Kód vazby obsahuje názvy vlastností (a pro jazyk C# někdy pole a metody). Když tedy vlastnost přejmenujete, budete také muset změnit všechny vazby, které na ni odkazují. Zapomeňte, že to vede k typickému příkladu chyby datové vazby a vaše aplikace se buď nezkompiluje, nebo se nespustí správně.

Objekty vazby vytvořené objekty {x:Bind} a {Binding} jsou z velké části funkčně ekvivalentní. {x:Bind} ale obsahuje informace o typu pro zdroj vazby a generuje zdrojový kód v době kompilace. S aplikací {x:Bind} získáte stejný druh detekce problémů, jaký získáte se zbytkem kódu. To zahrnuje ověření doby kompilace vašich vazeb výrazů a ladění nastavením zarážek ve zdrojovém kódu vygenerovaném jako částečnou třídu pro vaši stránku. Tyto třídy najdete v souborech ve složce obj s názvy jako (pro C#). <view name>.g.cs Pokud máte potíže s vazbou, zapněte v ladicím programu sady Microsoft Visual Studio přerušení neošetřených výjimek . Ladicí program v tomto okamžiku přeruší provádění a pak můžete ladit, co se nepovedlo. Kód vygenerovaný uživatelem {x:Bind} se řídí stejným vzorem pro každou část grafu zdrojových uzlů vazeb a informace v okně Zásobník volání vám pomohou určit posloupnost volání, která vedly k problému.

{Binding} nemá informace o typu pro zdroj vazby. Když ale spustíte aplikaci s připojeným ladicím programem, všechny chyby vazeb se zobrazí v okně Výstup v sadě Visual Studio.

Vytváření vazeb v kódu

Poznámka Tento oddíl platí jenom pro {Binding}, protože v kódu nelze vytvářet vazby {x:Bind} . Některé ze stejných výhod {x:Bind} je však možné dosáhnout pomocí DependencyObject.RegisterPropertyChangedCallback, což umožňuje registrovat oznámení o změnách u jakékoli vlastnosti závislosti.

Prvky uživatelského rozhraní můžete také připojit k datům pomocí procedurálního kódu místo XAML. Chcete-li to provést, vytvořte nový Binding objekt, nastavte příslušné vlastnosti a pak volejte FrameworkElement.SetBinding nebo BindingOperations.SetBinding. Vytváření vazeb prostřednictvím kódu programu je užitečné, když chcete zvolit hodnoty vlastností vazby za běhu nebo sdílet jednu vazbu mezi více ovládacími prvky. Všimněte si však, že po volání SetBinding nelze změnit hodnoty vlastnosti vazby.

Následující příklad ukazuje, jak implementovat vazbu v kódu.

<TextBox x:Name="MyTextBox" Text="Text"/>
// Create an instance of the MyColors class 
// that implements INotifyPropertyChanged.
MyColors textcolor = new MyColors();

// Brush1 is set to be a SolidColorBrush with the value Red.
textcolor.Brush1 = new SolidColorBrush(Colors.Red);

// Set the DataContext of the TextBox MyTextBox.
MyTextBox.DataContext = textcolor;

// Create the binding and associate it with the text box.
Binding binding = new Binding() { Path = new PropertyPath("Brush1") };
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding);
' Create an instance of the MyColors class 
' that implements INotifyPropertyChanged. 
Dim textcolor As New MyColors()

' Brush1 is set to be a SolidColorBrush with the value Red. 
textcolor.Brush1 = New SolidColorBrush(Colors.Red)

' Set the DataContext of the TextBox MyTextBox. 
MyTextBox.DataContext = textcolor

' Create the binding and associate it with the text box.
Dim binding As New Binding() With {.Path = New PropertyPath("Brush1")}
MyTextBox.SetBinding(TextBox.ForegroundProperty, binding)

Porovnání funkcí {x:Bind} a {Binding}

Vlastnost {x:Bind} vs. {Binding} Poznámky
Cesta je výchozí vlastnost. {x:Bind a.b.c}
-
{Binding a.b.c}
Path – vlastnost {x:Bind Path=a.b.c}
-
{Binding Path=a.b.c}
V x:Bind je cesta ve výchozím nastavení kořenem na stránce, nikoli DataContext.
Indexer {x:Bind Groups[2].Title}
-
{Binding Groups[2].Title}
Vytvoří vazbu na zadanou položku v kolekci. Podporují se pouze celočíselné indexy.
Připojené vlastnosti {x:Bind Button22.(Grid.Row)}
-
{Binding Button22.(Grid.Row)}
Připojené vlastnosti jsou zadány pomocí závorek. Pokud vlastnost není deklarována v oboru názvů XAML, předpona ho nahraďte oborem názvů XML, který by měl být namapován na obor názvů kódu v záhlaví dokumentu.
Odlévání {x:Bind groups[0].(data:SampleDataGroup.Title)}
-
Pro {Binding} není potřeba.
Přetypování se zadává pomocí závorek. Pokud vlastnost není deklarována v oboru názvů XAML, předpona ho nahraďte oborem názvů XML, který by měl být namapován na obor názvů kódu v záhlaví dokumentu.
Převodník {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}}
Převaděče musí být deklarovány v kořenovém adresáři Stránky/ResourceDictionary nebo v Souboru App.xaml.
ConverterParameter, ConverterLanguage {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
-
{Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}
Převaděče musí být deklarovány v kořenovém adresáři Stránky/ResourceDictionary nebo v Souboru App.xaml.
TargetNullValue {x:Bind Name, TargetNullValue=0}
-
{Binding Name, TargetNullValue=0}
Používá se, když list vazbového výrazu má hodnotu null. Pro řetězcovou hodnotu použijte jednoduché uvozovky.
Náhradní hodnota {x:Bind Name, FallbackValue='empty'}
-
{Binding Name, FallbackValue='empty'}
Používá se, když jakákoli část cesty pro vazbu (s výjimkou listu) má hodnotu null.
ElementName {x:Bind slider1.Value}
-
{Binding Value, ElementName=slider1}
S {x:Bind} jste svázání s polem; Cesta je ve výchozím nastavení kořenem stránky, takže ke všem pojmenovaným elementům je možné přistupovat prostřednictvím jeho pole.
RelativeSource: Self <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />
-
<Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... />
V {x:Bind} pojmenujte prvek a použijte jeho název v cestě.
RelativeSource: TemplatedParent Pro {x:Bind} není potřeba.
-
{Binding <path>, RelativeSource={RelativeSource TemplatedParent}}
U typu TargetType {x:Bind} u ControlTemplate označuje vazbu na nadřazenou položku šablony. Pro {Binding} běžnou vazbu šablon lze použít v šablonách ovládacích prvků pro většinu použití. Ale použijte TemplatedParent, kde potřebujete použít převaděč nebo obousměrnou vazbu.<
Zdroj Pro {x:Bind} není potřeba.
-
<ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/>
Pro {x:Bind} můžete přímo použít pojmenovaný prvek, použít vlastnost nebo statickou cestu.
Mode {x:Bind Name, Mode=OneWay}
-
{Binding Name, Mode=TwoWay}
Režim může být OneTime, OneWay nebo TwoWay. {x:Bind} má výchozí hodnotu OneTime; {Binding} ve výchozím nastavení je OneWay.
UpdateSourceTrigger {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
-
{Binding UpdateSourceTrigger=PropertyChanged}
UpdateSourceTrigger může být Default, LostFocus nebo PropertyChanged. {x:Bind} nepodporuje UpdateSourceTrigger=Explicit. {x:Bind} používá chování PropertyChanged pro všechny případy s výjimkou TextBox.Text, kde používá chování LostFocus.