Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Fontos API-k
Megjegyzés:
Ez a témakör részletesen ismerteti az adatkötési funkciókat. Rövid, gyakorlati bevezetésért tekintse meg az adatkötés áttekintését.
Ez a témakör a Windows.UI.Xaml.Data névtérben található API-k adatkötéséről szól.
Az adatkötéssel az alkalmazás felhasználói felülete megjelenítheti az adatokat, és igény szerint szinkronban maradhat az adatokkal. Az adatkötés lehetővé teszi, hogy elkülönítse az adatok aggodalmait a felhasználói felülettől, és ez egyszerűbb elméleti modellt, valamint az alkalmazás jobb olvashatóságát, tesztelhetőségét és karbantarthatóságát eredményezi.
Az adatkötéssel egyszerűen megjelenítheti az adatforrás értékeit a felhasználói felület első megjelenítésekor, de nem válaszolhat az értékek változásaira. Ez egy egyszeri kötési mód, és jól működik egy olyan érték esetében, amely futásidőben nem változik. Másik lehetőségként dönthet úgy is, hogy "megfigyeli" az értékeket, és módosítja a felhasználói felületet, amikor azok változnak. Ezt a módot egyirányúnak nevezik, és jól működik az írásvédett adatokhoz. Végső soron úgy is dönthet, hogy megfigyeli és frissíti a felhasználói felületen lévő értékeket, így a rendszer automatikusan visszaküldi az adatforrásba a felhasználó által végrehajtott módosításokat. Ezt a módot kétirányúnak nevezik, és jól működik az olvasási-írási adatokhoz. Íme néhány példa.
- Az egyszeri módban a rendszerképet az aktuális felhasználó fényképéhez kötheti.
- Az egyirányú módban a ListView-t az újságszakaszok szerint csoportosított valós idejű hírcikkek gyűjteményéhez kötheti.
- A kétirányú módban a TextBoxot egy ügyfél nevéhez kötheti egy űrlapon.
A módtól függetlenül kétféle kötés létezik, és mindkettő általában a felhasználói felületi korrektúrában van deklarálva. Választhatja a {x:Bind} korrektúrakiterjesztést vagy a {Binding} korrektúrakiterjesztést. És akár a kettő keverékét is használhatja ugyanabban az alkalmazásban – még ugyanazon a felhasználói felületen is. A(z) {x:Bind} windows 10-hez készült, és jobb teljesítménnyel rendelkezik. A jelen témakörben ismertetett összes részlet mindkét kötéstípusra vonatkozik, hacsak nem mondjuk kifejezetten másként.
Mintaalkalmazások a(z) {x:Bind} bemutatásához
Mintaalkalmazások a(z) {Binding} bemutatásához
- Töltse le a Bookstore1 alkalmazást.
- Töltse le a Bookstore2 alkalmazást.
Minden kötés magában foglalja ezeket a darabokat
- Kötési forrás. Ez a kötés adatainak forrása, és bármely olyan osztály egy példánya lehet, amelynek tagjai olyan értékeket tartalmaznak, amelyeket meg szeretne jeleníteni a felhasználói felületen.
- Kötési cél. Ez a felhasználói felületen található FrameworkElementDependencyProperty tulajdonsága, amely megjeleníti az adatokat.
- Kötésobjektum. Ez az a darab, amely adatértékeket továbbít a forrásból a célba, és opcionálisan a célból vissza a forrásba. A kötési objektum XAML-betöltéskor jön létre a(z) {x:Bind} vagy {Binding} korrektúrakiterjesztésből.
A következő szakaszokban közelebbről is megvizsgáljuk a kötés forrását, a kötési célt és a kötési objektumot. A szakaszokat összekapcsoljuk a gomb tartalmának egy NextButtonText nevű karakterlánctulajdonsághoz való kötésének példájával, amely egy HostViewModel nevű osztályhoz tartozik.
Kötés forrása
Íme egy nagyon kezdetleges implementáció egy osztályhoz, amelyet kötési forrásként használhatunk.
Ha C++/WinRT-t használ, adjon hozzá új Midl-fájl (.idl) elemeket a projekthez, a C++/WinRT-kód alábbi felsorolásában látható módon. Cserélje le az új fájlok tartalmát a listaelemben látható MIDL 3.0 kódra, hozza létre HostViewModel.h a létrehozandó projektet, majd .cppadjon hozzá kódot a létrehozott fájlokhoz a listaelemnek megfelelően. A létrehozott fájlokról és a projektbe való másolásukról további információt az XAML-vezérlők; A C++/WinRT tulajdonsághoz való kötés című témakörben talál.
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;
}
...
A HostViewModel és tulajdonsága, a NextButtonText csak egyszeri kötéshez megfelelő. Az egyirányú és a kétirányú kötések azonban rendkívül gyakoriak, és az ilyen típusú kötésekben a felhasználói felület automatikusan frissül a kötésforrás adatértékeinek változásaira reagálva. Ahhoz, hogy az ilyen típusú kötések megfelelően működjenek, a kötési forrást "megfigyelhetővé" kell tennie a kötési objektumon. Ezért a példánkban, ha egyirányú vagy kétirányú kötést szeretnénk a NextButtonText tulajdonsághoz, akkor a tulajdonság értékének futásidőben bekövetkező módosításait megfigyelhetővé kell tenni a kötési objektumon.
Ennek egyik módja, ha a DependencyObjectből származtatja a kötésforrást képviselő osztályt, és egy DependencyPropertyen keresztül elérhetővé tesz egy adatértéket. Így válik megfigyelhetővé egy FrameworkElement . A FrameworkElements jó kötési források közvetlenül a dobozból.
Az osztály megfigyelhetővé tételének egyszerűbb módja – és a már alaposztálysal rendelkező osztályokhoz szükséges – a System.ComponentModel.INotifyPropertyChanged implementálása. Ez valójában csak magában foglalja a PropertyChanged nevű egyetlen esemény implementálását. Alább látható egy példa a HostViewModel használatára.
...
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);
}
...
Most már megfigyelhető a NextButtonText tulajdonság. Ha egyirányú vagy kétirányú kötést hoz létre a tulajdonsághoz (a későbbiekben bemutatjuk, hogyan), az eredményként kapott kötési objektum feliratkozik a PropertyChanged eseményre. Az esemény felmerülésekor a kötésobjektum kezelője egy argumentumot kap, amely a módosított tulajdonság nevét tartalmazza. Így tudja a kötési objektum, hogy melyik tulajdonság értéke legyen újraolvasva.
Ahhoz, hogy ne kelljen többször implementálnia a fenti mintát, ha C#-ot használ, akkor egyszerűen származtathatja a QuizGame-mintában (a "Common" mappában) található BindableBase alaposztályból. Íme egy példa arra, hogyan néz ki.
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.
Megjegyzés:
C++/WinRT esetén az alkalmazásban az alaposztályból származó futtatókörnyezeti osztályokat összeállítható osztálynak nevezzük. És vannak megkötések a összeállítható osztályok körül. Ahhoz, hogy egy alkalmazás megfeleltethesse a Visual Studio és a Microsoft Store által a beküldések ellenőrzéséhez használt Windows-alkalmazástanúsítvány-teszteket (és így ahhoz, hogy az alkalmazás sikeresen betölthető legyen a Microsoft Store-ba), a összeállítható osztálynak végül egy Windows-alaposztályból kell származnia. Ez azt jelenti, hogy az öröklési hierarchia gyökerénél lévő osztálynak Windows.* névtérből származó típusnak kell lennie. Ha egy futtatókörnyezeti osztályt egy alaposztályból kell származtatnia – például egy BindableBase-osztályt kell implementálnia az összes olyan nézetmodellhez, amelyből származni szeretne –, akkor a Windows.UI.Xaml.DependencyObject parancsból származtathatja.
A PropertyChanged esemény sztring.üres vagy null argumentummal való emelése azt jelzi, hogy az objektum összes nem indexelő tulajdonságát újra kell olvasni. Az eseményt úgy állíthatja be, hogy jelezze, hogy az objektum indexelői tulajdonságai módosultak az adott indexelőkhöz tartozó "Item[indexer]" argumentummal (ahol az indexelő az indexelő értéke), vagy az összes indexelőhöz tartozó "Item[]" értékkel.
A kötési forrásokat egyetlen objektumként lehet kezelni, amelynek tulajdonságai adatokat tartalmaznak, vagy objektumgyűjteményként. A C# és a Visual Basic kódban egyszeri kötést végezhet egy olyan objektumhoz, amely implementálja a List(Of T) elemet egy olyan gyűjtemény megjelenítéséhez, amely futásidőben nem változik. Megfigyelhető gyűjtemény esetén (megfigyelve, hogy az elemeket hozzáadják és eltávolítják a gyűjteményből), ehelyett egyirányú kötést kell létrehozni az ObservableCollection(Of T) elemhez. A C++/CX kódban megfigyelhető és nem megfigyelhető gyűjteményekhez is csatlakozhat a Vector<T-hez> , a C++/WinRT-nek pedig saját típusai vannak. A saját gyűjteményosztályokhoz való kötéshez használja az alábbi táblázatban található útmutatást.
| Scenario | C# és VB (CLR) | C++/WinRT | C++/CX |
|---|---|---|---|
| Kötés egy objektumhoz. | Bármilyen objektum lehet. | Bármilyen objektum lehet. | Az objektumnak BindableAttribute-tal vagy ICustomPropertyProvider implementálással kell rendelkeznie. |
| Tulajdonságmódosítási értesítések lekérése kötött objektumból. | Az objektumnak implementálnia kell az INotifyPropertyChanged parancsot. | Az objektumnak implementálnia kell az INotifyPropertyChanged parancsot. | Az objektumnak implementálnia kell az INotifyPropertyChanged parancsot. |
| Kötés gyűjteményhez. | List(Of T) | IInspectable IVector vagy IBindableObservableVector. Lásd : XAML-elemek vezérlői; kötés C++/WinRT-gyűjteményhez és gyűjteményekhez C++/WinRT használatával. | Vektor<T> |
| Gyűjteménymódosítási értesítések lekérése egy kötött gyűjteményből. | ObservableCollection(Of T) | Az IInspectableIObservableVectorja. Például winrt::single_threaded_observable_vector<T>. | IObservableVector<T>. Vektor<T> implementálja ezt az interfészt. |
| Implementáljon egy kötést támogató gyűjteményt. | A List(of T) kiterjesztése vagy az IList, az IList(of Object), az IEnumerable vagy az IEnumerable(of Object) implementálása. Az általános IList(Of T) és az IEnumerable(Of T) kötése nem támogatott. | Implementálja az IInspectableIVectorját. Lásd : XAML-elemek vezérlői; kötés C++/WinRT-gyűjteményhez és gyűjteményekhez C++/WinRT használatával. | IBindableVector, IBindableIterable, IVector<Object^>, IIterable<Object^>, IVector<IInspectable*> vagy IIterable<IInspectable*> implementálása. Az általános IVector<T-hez> és az IIterable T-hez<> való kötés nem támogatott. |
| Olyan gyűjtemény implementálása, amely támogatja a gyűjteménymódosítási értesítéseket. | Az ObservableCollection(Of T) kiterjesztése vagy implementálása (nem általános) IList és INotifyCollectionChanged. | Az IInspectableIObservableVector vagy IBindableObservableVector implementálása. | Az IBindableVector és az IBindableObservableVector implementálása. |
| Implementáljon egy gyűjteményt, amely támogatja a növekményes betöltést. | Az ObservableCollection(Of T) kiterjesztése vagy implementálása (nem általános) IList és INotifyCollectionChanged. Emellett implementálja az ISupportIncrementalLoadinget is. | Az IInspectableIObservableVector vagy IBindableObservableVector implementálása. Az ISupportIncrementalLoading implementálása | Implementálja az IBindableVector, az IBindableObservableVector és az ISupportIncrementalLoading szolgáltatást. |
A listavezérlőket tetszőlegesen nagy adatforrásokhoz kötheti, és növekményes betöltéssel továbbra is magas teljesítményt érhet el. A listavezérlőket például anélkül kötheti a Bing-rendszerkép-lekérdezés eredményeihez, hogy egyszerre kellene betöltenie az összes találatot. Ehelyett csak néhány találatot tölt be azonnal, és szükség szerint további eredményeket tölt be. A növekményes betöltés támogatásához az ISupportIncrementalLoading-t olyan adatforráson kell implementálnia, amely támogatja a gyűjteménymódosítási értesítéseket. Amikor az adatkötési motor több adatot kér, az adatforrásnak meg kell adnia a megfelelő kéréseket, integrálnia kell az eredményeket, majd el kell küldenie a megfelelő értesítéseket a felhasználói felület frissítéséhez.
Kötési cél
Az alábbi két példában a Button.Content tulajdonság a kötési cél, értéke pedig egy korrektúrakiterjesztés, amely deklarálja a kötési objektumot. Először {x:Bind} jelenik meg, majd {Kötés}. A korrektúra kötéseinek deklarálása gyakori eset (kényelmes, olvasható és eszközlhető). Azonban elkerülheti a korrektúra használatát, és igény szerint (programozott módon) létrehozhatja a Kötés osztály egy példányát, ha szükséges.
<Button Content="{x:Bind ...}" ... />
<Button Content="{Binding ...}" ... />
Ha C++/WinRT vagy Visual C++ összetevőbővítményeket (C++/CX) használ, akkor hozzá kell adnia a BindableAttribute attribútumot minden olyan futtatókörnyezeti osztályhoz, amellyel a {Binding} jelölőbővítményt használni szeretné.
Fontos
C++/WinRT használata esetén a BindableAttribute attribútum akkor érhető el, ha telepítette a Windows SDK 10.0.17763.0-s verzióját (Windows 10, 1809-es verzió) vagy újabb verzióját. Az attribútum nélkül implementálnia kell az ICustomPropertyProvider és az ICustomProperty interfészeket a {Binding} korrektúrabővítmény használatához.
{x:Bind} használatával deklarált kötési objektum
Az {x:Bind} korrektúra létrehozásához egy lépésre van szükség. A kötési forrásosztályt a korrektúraoldalt képviselő osztályból kell közzétennünk. Ezt úgy tesszük, hogy hozzáadunk egy (ebben az esetben HostViewModel típusú) tulajdonságot a MainPage laposztályunkhoz.
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;
}
...
Ezzel közelebbről megvizsgálhatjuk a kötési objektumot deklaráló korrektúrát. Az alábbi példa ugyanazt a Button.Content kötési célt használja, amelyet korábban a "Kötési cél" szakaszban használtunk, és azt mutatja, hogy a HostViewModel.NextButtonText tulajdonsághoz van kötve.
<!-- MainPage.xaml -->
<Page x:Class="DataBindingInDepth.Mainpage" ... >
<Button Content="{x:Bind Path=ViewModel.NextButtonText, Mode=OneWay}" ... />
</Page>
Figyelje meg az elérési úthoz megadott értéket. Ezt az értéket a lap kontextusában értelmezi a rendszer, és ebben az esetben az elérési út a MainPage laphoz most hozzáadott ViewModel tulajdonságra való hivatkozással kezdődik. Ez a tulajdonság egy HostViewModel-példányt ad vissza, így a HostViewModel.NextButtonText tulajdonság eléréséhez be tudunk lépni ebbe az objektumba. Megadjuk a Módot, hogy felülbíráljuk az egyszeri {x:Bind} alapértelmezett értékét.
Az Elérési út tulajdonság számos szintaxisbeállítást támogat a beágyazott tulajdonságokhoz, a csatolt tulajdonságokhoz, valamint az egész számhoz és a sztringindexelőkhöz való kötéshez. További információ: Tulajdonság-elérési út szintaxisa. A sztringindexelőkhöz való kötés az ICustomPropertyProvider implementálása nélkül teszi lehetővé a dinamikus tulajdonságokhoz való kötést. További beállítások: {x:Bind} korrektúrakiterjesztés.
Annak szemléltetéséhez, hogy a HostViewModel.NextButtonText tulajdonság valóban megfigyelhető, vegyen fel egy Click eseménykezelőt a gombra, és frissítse a HostViewModel.NextButtonText értékét. Buildelje, futtassa és kattintson a gombra a gomb tartalomfrissítésének értékének megtekintéséhez.
// 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");
}
Megjegyzés:
A TextBox.Text módosításait a rendszer kétirányú kötött forrásba küldi, amikor a Szövegdoboz elveszíti a fókuszt, és nem minden felhasználói billentyűleütés után.
DataTemplate és x:DataType
A DataTemplate-ban (akár elemsablonként, tartalomsablonként, akár fejlécsablonként) az Elérési út értékét nem a lap kontextusában, hanem a sablonként használt adatobjektum kontextusában értelmezi a rendszer. Ha {x:Bind}-t használ egy adatsablonban, hogy a kötései érvényesíthetők legyenek (és a számukra létrehozott hatékony kód) fordításkor, a DataTemplate-nakx:DataType használatával deklarálnia kell az adatobjektum típusát. Az alábbi példa egy SampleDataGroup objektumgyűjteményhez kötött elemvezérlő ItemTemplate elemtáblájaként használható.
<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>
Gyengén gépelt objektumok az elérési úton
Tegyük fel például, hogy egy SampleDataGroup nevű típussal rendelkezik, amely egy Title nevű sztringtulajdonságot implementál. És van egy MainPage.SampleDataGroupAsObject tulajdonsága, amely típusobjektum, de valójában a SampleDataGroup egy példányát adja vissza. A kötés <TextBlock Text="{x:Bind SampleDataGroupAsObject.Title}"/> fordítási hibát fog eredményezni, mert a Title tulajdonság nem található a típusobjektumon. Ennek a megoldásnak az a megoldása, ha a következőhöz hasonló módon ad hozzá egy leadott elemet az Elérési út szintaxisához: <TextBlock Text="{x:Bind ((data:SampleDataGroup)SampleDataGroupAsObject).Title}"/>. Íme egy másik példa, amelyben az elem objektumként deklarálva van, de valójában textBlock: <TextBlock Text="{x:Bind Element.Text}"/>. És a leadott jogorvoslati a probléma: <TextBlock Text="{x:Bind ((TextBlock)Element).Text}"/>.
Ha az adatok aszinkron módon töltődik be
A(z) {x:Bind} támogatására szolgáló kód fordítási időben jön létre a lapok részleges osztályaiban. Ezek a fájlok a mappában obj találhatók, például (C#) <view name>.g.csnéven. A létrehozott kód tartalmaz egy kezelőt a lap betöltési eseményéhez, és ez a kezelő meghívja az Inicializálás metódust egy olyan generált osztályon, amely az oldal kötéseit képviseli.
Inicializálja az Update-et , hogy megkezdje az adatok áthelyezését a kötési forrás és a cél között.
A betöltés közvetlenül az oldal vagy a felhasználói vezérlő első mértéke előtt történik. Így ha az adatok aszinkron módon vannak betöltve, előfordulhat, hogy az inicializálás meghívásának idejére nem lesznek készek. Így az adatok betöltése után kényszerítheti az egyszeri kötések inicializálását hívással this.Bindings.Update();. Ha csak egyszeri kötésekre van szüksége az aszinkron módon betöltött adatokhoz, akkor sokkal olcsóbb inicializálni őket így, mint egyirányú kötésekkel, és figyelni a módosításokat. Ha az adatok nem mennek át részletes módosításokon, és ha azokat valószínűleg egy adott művelet részeként frissítik, akkor a kötéseket egyszeri alkalommal is végrehajthatja, és bármikor kényszerítheti a manuális frissítést a Frissítés hívásával.
Megjegyzés:
A(z) {x:Bind} nem alkalmas késői kötött forgatókönyvekre, például egy JSON-objektum szótárszerkezetének navigálására vagy a kacsagépelésre. A "kacsagépelés" a tulajdonságnevek lexikális egyezései alapján történő gépelés gyenge formája (ahogy a "ha sétál, úszik és reng, mint egy kacsa, akkor ez egy kacsa"). Kacsagépelés esetén az Age tulajdonsághoz való kötés egyformán megfelel egy Személyvagy Bor objektumnak (feltéve, hogy ezek a típusok mindegyike rendelkezik Kor tulajdonsággal). Ezekben a forgatókönyvekben használja a {Binding} korrektúrabővítményt.
A(z) {Binding} használatával deklarált kötési objektum
Ha C++/WinRT vagy Visual C++ összetevőbővítményeket (C+++/CX) használ, akkor a {Binding} korrektúrabővítmény használatához hozzá kell adnia a BindableAttribute attribútumot minden olyan futtatókörnyezeti osztályhoz, amelyhez kötést szeretne kötni. A(z) {x:Bind} használatához nincs szükség erre az attribútumra.
// HostViewModel.idl
// Add this attribute:
[Windows.UI.Xaml.Data.Bindable]
runtimeclass HostViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
...
Fontos
C++/WinRT használata esetén a BindableAttribute attribútum akkor érhető el, ha telepítette a Windows SDK 10.0.17763.0-s verzióját (Windows 10, 1809-es verzió) vagy újabb verzióját. Az attribútum nélkül implementálnia kell az ICustomPropertyProvider és az ICustomProperty interfészeket a {Binding} korrektúrabővítmény használatához.
A {Binding} alapértelmezés szerint azt feltételezi, hogy a korrektúralap DataContext eleméhez köt. Ezért úgy állítjuk be a lap DataContext elemét, hogy a kötés forrásosztályának egy példánya legyen (ebben az esetben HostViewModel típusú). Az alábbi példában a kötésobjektumot deklaráló korrektúra látható. Ugyanazt a Button.Content kötési célt használjuk, amelyet korábban a "Kötési cél" szakaszban használtunk, és a HostViewModel.NextButtonText tulajdonsághoz kötődünk.
<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");
}
Figyelje meg az elérési úthoz megadott értéket. Ezt az értéket a lap DataContext környezetében értelmezi a rendszer, amely ebben a példában a HostViewModel egy példányára van állítva. Az elérési út a HostViewModel.NextButtonText tulajdonságra hivatkozik. Kihagyhatjuk a módot, mert az egyirányú {Binding} alapértelmezett értéke itt működik.
A felhasználói felületi elem DataContextjének alapértelmezett értéke a szülő öröklött értéke. Természetesen felülbírálhatja ezt az alapértelmezett beállítást a DataContext explicit beállításával, amelyet a gyermekek alapértelmezés szerint örökölnek. A DataContext explicit beállítása egy elemre akkor hasznos, ha több olyan kötést szeretne használni, amelyek ugyanazt a forrást használják.
A kötési objektumok forrástulajdonságokkal rendelkeznek, amelyek alapértelmezés szerint annak a felhasználói felületi elemnek a DataContext elemére vannak beállítva, amelyen a kötés deklarálva van. Ezt az alapértelmezett értéket felülbírálhatja úgy, hogy explicit módon beállítja a Forrás, a RelativeSource vagy az ElementName értéket a kötésen (részletekért lásd a {Binding} cikket).
Egy DataTemplate-fájlon belül a DataContext automatikusan a sablonozott adatobjektumra van állítva. Az alábbi példa egy tetszőleges típusú gyűjteményhez kötött elemvezérlő ItemTemplate elemtáblájaként használható, amely a Cím és leírás nevű karakterlánc-tulajdonságokkal rendelkezik.
<DataTemplate x:Key="SimpleItemTemplate">
<StackPanel Orientation="Vertical" Height="50">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Description"/>
</StackPanel>
</DataTemplate>
Megjegyzés:
Alapértelmezés szerint a TextBox.Text módosításai kétirányú kötött forrásba kerülnek, amikor a Szövegdoboz elveszíti a fókuszt. Ha azt szeretné, hogy a módosítások minden felhasználói billentyűleütés után el legyenek küldve, állítsa az UpdateSourceTriggerttulajdonságra a kötésen a korrektúrában. Az UpdateSourceTrigger explicit értékre állításával teljes mértékben átveheti a módosításokat a forrásnak küldött módosítások felett. Ezután kezelheti a szövegmező eseményeit (általában TextBox.TextChanged), meghívja a GetBindingExpression parancsot a célon egy BindingExpression objektum lekéréséhez, végül meghívja a BindingExpression.UpdateSource parancsot az adatforrás programozott frissítéséhez.
Az Elérési út tulajdonság számos szintaxisbeállítást támogat a beágyazott tulajdonságokhoz, a csatolt tulajdonságokhoz, valamint az egész számhoz és a sztringindexelőkhöz való kötéshez. További információ: Tulajdonság-elérési út szintaxisa. A sztringindexelőkhöz való kötés az ICustomPropertyProvider implementálása nélkül teszi lehetővé a dinamikus tulajdonságokhoz való kötést. Az ElementName tulajdonság elemről elemre kötés esetén hasznos. A RelativeSource tulajdonságnak több felhasználási módja is van, amelyek közül az egyik a ControlTemplate-on belüli sablonkötés hatékonyabb alternatívája. További beállításokért tekintse meg a {Binding} korrektúrabővítményt és a Kötés osztályt.
Mi történik, ha a forrás és a cél nem azonos típusú?
Ha egy felhasználói felületi elem láthatóságát egy logikai tulajdonság értéke alapján szeretné szabályozni, vagy ha egy numerikus érték tartományának vagy trendjének függvényét képező színnel szeretne megjeleníteni egy felhasználói felületi elemet, vagy ha egy dátum- és/vagy időértéket szeretne megjeleníteni egy olyan felhasználói felületi elemtulajdonságban, amely sztringre számít, ezután át kell alakítania az értékeket egyik típusból a másikba. Lesznek olyan esetek, amikor a megfelelő megoldás a kötési forrásosztályból egy másik, megfelelő típusú tulajdonság felfedése, és a konverziós logika beágyazása és tesztelése. Ez azonban nem rugalmas és nem skálázható, ha nagy számú vagy nagy kombinációval rendelkezik a forrás- és céltulajdonságok között. Ebben az esetben több lehetősége is van:
- {x:Bind} használata esetén közvetlenül egy függvényhez kötéssel végezheti el az átalakítást
- Vagy megadhat egy értékkonvertert, amely az átalakítás végrehajtására tervezett objektum
Értékkonverterek
Íme egy értékkonverter, amely egy egyszeri vagy egyirányú kötéshez alkalmas, amely egy DateTime-értéket a hónapokat tartalmazó sztringértékké alakít át. Az osztály implementálja az IValueConvertert.
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.
Ezt az értékkonvertert pedig így használhatja fel a kötésobjektum-jelölőben.
<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}}"/>
A kötési motor meghívja a Konvertálás és a ConvertBack metódust, ha a Kötés konverter paramétere definiálva van. Amikor a forrásból adatokat ad át, a kötési motor meghívja a Konvertálást , és átadja a visszaadott adatokat a célnak. Amikor adatokat ad át a céltól (kétirányú kötés esetén), a kötési motor meghívja a ConvertBacket , és átadja a visszaadott adatokat a forrásnak.
A konverter opcionális paraméterekkel is rendelkezik: ConverterLanguage, amely lehetővé teszi az átalakításban használni kívánt nyelv megadását, és a ConverterParameter, amely lehetővé teszi a konverziós logika paraméterének átadását. Konverterparamétert használó példa: IValueConverter.
Megjegyzés:
Ha hiba történt az átalakítás során, ne tegyen kivételt. Ehelyett adja vissza a DependencyProperty.UnsetValue értéket, amely leállítja az adatátvitelt.
Ha egy alapértelmezett értéket szeretne megjeleníteni, amelyet akkor kell használni, amikor a kötési forrás nem oldható fel, állítsa be a FallbackValue tulajdonságot a kötésobjektumon a korrektúrában. Ez hasznos a konvertálási és formázási hibák kezeléséhez. Hasznos olyan forrástulajdonságokhoz is kötni, amelyek nem feltétlenül léteznek a heterogén típusú kötött gyűjtemény összes objektumán.
Ha egy szövegvezérlőt olyan értékhez köt, amely nem sztring, az adatkötési motor sztringgé alakítja az értéket. Ha az érték hivatkozástípus, az adatkötési motor lekéri a sztringértéket az ICustomPropertyProvider.GetStringRepresentation vagy az IStringable.ToString hívásával, ha elérhető, és más módon meghívja az Object.ToString parancsot. Vegye figyelembe azonban, hogy a kötési motor figyelmen kívül hagy minden Olyan ToString-implementációt , amely elrejti az alaposztályú implementációt. Az alosztály implementációinak felül kell bírálnia az alaposztály ToString metódusát . Hasonlóképpen, az natív nyelvekben az összes felügyelt objektum az ICustomPropertyProvider és az IStringable implementálásához tűnik. A GetStringRepresentation és az IStringable.ToString hívásai azonban az Object.ToString vagy a metódus felülbírálása felé vannak irányítva, és soha nem kerülnek olyan új ToString-implementációba , amely elrejti az alaposztály-implementációt.
Megjegyzés:
A Windows 10 1607-es verziójától kezdve az XAML-keretrendszer beépített logikai és láthatósági konvertert biztosít. A konverter a látható enumerálási értékhez igaz, a hamis pedig összecsukva van, így konverter létrehozása nélkül is köthet láthatósági tulajdonságot egy logikai értékhez. A beépített konverter használatához az alkalmazás minimális cél SDK-verziójának 14393-as vagy újabb verziónak kell lennie. Nem használható, ha az alkalmazás a Windows 10 korábbi verzióit célozza meg. További információ a célverziókról: Adaptív verziókód.
Függvénykötés a következőben: {x:Bind}
A(z) {x:Bind} lehetővé teszi, hogy a kötési útvonal utolsó lépése függvény legyen. Ez konverziók végrehajtására és több tulajdonságtól függő kötések végrehajtására használható. Függvények megtekintése az x:Bind fájlban
Elem–elem kötés
Egy XAML-elem tulajdonságát egy másik XAML-elem tulajdonságához kötheti. Íme egy példa a korrektúra megjelenésére.
<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />
Fontos
A C++/WinRT használatával történő elem-elem kötéshez szükséges munkafolyamatot lásd : Elem–elem kötés.
Erőforrás-szótárak a következővel: {x:Bind}
A(z) {x:Bind} jelölőbővítmény a kódgenerálástól függ, ezért olyan kód mögötti fájlra van szüksége, amely egy olyan konstruktort tartalmaz, amely meghívja az InitializeComponentet (a generált kód inicializálásához). Az erőforrás szótárát úgy használhatja újra, hogy a fájlnévre való hivatkozás helyett példányosítja annak típusát (hogy az InitializeComponent legyen meghívva). Íme egy példa arra, hogy mi a teendő, ha rendelkezik egy meglévő erőforrás-szótárval, és a(z) {x:Bind} fájlt szeretné használni benne.
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>
{x:Bind} és {Binding} keverése újrafelhasználható stílusban
Bár az előző példában a(z) {x:Bind} használata jelent meg a DataTemplatesben, létrehozhat olyan újrafelhasználható stílusokat is, amelyek {x:Bind} és {Binding} korrektúrakiterjesztéseket is kombinálnak. Ez akkor hasznos, ha bizonyos tulajdonságokat a(z) {x:Bind} és más tulajdonságok használatával szeretne összekötni az ismert értékek fordításához a(z) {Binding} használatával.
Íme egy példa, amely bemutatja, hogyan hozhat létre újrafelhasználható gombstílust, amely mindkét kötési módszert használja:
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);
}
}
Használat a MainPage.xaml-ben futtatókörnyezeti értékeket biztosító ViewModel-lel:
<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 (a futtatókörnyezeti kötési értékeket biztosító DataContext):
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;
}
}
Ebben a példában:
- A(z) {Binding} a DataContexttől függő tulajdonságokhoz használható (ButtonBackgroundBrush, ButtonForegroundBrush, ButtonHoverBrush)
- A(z) {x:Bind} olyan tulajdonságokhoz használatos, amelyek fordítási ideje ismert, és maga a ResourceDictionary része (DefaultIndicatorBrush, DefaultPressedBrush)
- A stílus újrafelhasználható, és bármely gombra alkalmazható
- A futtatókörnyezeti feldolgozás a DataContexten keresztül lehetséges, miközben a statikus elemek {x:Bind} teljesítménye továbbra is előnyös
Eseménykötés és ICommand
A(z) {x:Bind} támogatja az eseménykötés nevű funkciót. Ezzel a funkcióval megadhatja egy esemény kezelőjét egy kötéssel, amely további lehetőség az események kezelésére egy metódussal a kód mögötti fájlon. Tegyük fel, hogy rootFrame tulajdonsága van a MainPage osztályban.
public sealed partial class MainPage : Page
{
...
public Frame RootFrame { get { return Window.Current.Content as Frame; } }
}
Ezután egy gomb Kattintás eseményét a RootFrame tulajdonság által visszaadott Frame objektum metódusához kötheti. Vegye figyelembe, hogy a gomb IsEnabled tulajdonságát is ugyanahhoz a kerethez egy másik taghoz kötjük.
<AppBarButton Icon="Forward" IsCompact="True"
IsEnabled="{x:Bind RootFrame.CanGoForward, Mode=OneWay}"
Click="{x:Bind RootFrame.GoForward}"/>
A túlterhelt metódusok nem használhatók esemény kezelésére ezzel a technikával. Ha az eseményt kezelő metódusnak vannak paraméterei, akkor mindegyiknek hozzárendelhetőnek kell lennie az esemény összes paraméterének típusából. Ebben az esetben a Frame.GoForward nincs túlterhelve, és nincsenek paraméterei (de akkor is érvényes lenne, ha két objektumparamétert vett volna igénybe). A Frame.GoBack azonban túlterhelt, ezért ezt a módszert nem használhatjuk ezzel a technikával.
Az eseménykötési technika hasonló a parancsok implementálásához és használatához (a parancsok olyan tulajdonságok, amelyek az ICommand felületet implementáló objektumot adnak vissza). A (z) {x:Bind} és a {Binding} egyaránt parancsokkal dolgozik. Annak érdekében, hogy ne kelljen többször implementálnia a parancsmintát, használhatja a DelegateCommand segédosztályt, amelyet a QuizGame-minta (a "Common" mappában) talál.
Kötés mappák vagy fájlok gyűjteményéhez
A Windows.Storage névtér API-jait használhatja a mappa- és fájladatok lekéréséhez. A különböző GetFilesAsync, GetFoldersAsync és GetItemsAsync metódusok azonban nem a vezérlőelemek kötésére alkalmas értékeket adnak vissza. Ehelyett a FileInformationFactory osztály GetVirtualizedFilesVector, GetVirtualizedFoldersVector és GetVirtualizedItemsVector metódusainak visszatérési értékeihez kell kapcsolódnia. A StorageDataSource és a GetVirtualizedFilesVector minta alábbi kódpéldája a tipikus használati mintát mutatja. Ne felejtse el deklarálni a picturesLibrary képességet az alkalmazáscsomag-jegyzékben, és győződjön meg arról, hogy vannak képek a Képek tár mappájában.
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;
}
Ezzel a módszerrel általában írásvédett nézetet hozhat létre a fájl- és mappaadatokról. Létrehozhat kétirányú kötéseket a fájl- és mappatulajdonságokhoz, például lehetővé teheti, hogy a felhasználók zenenézetben értékeljenek egy dalt. A módosítások azonban nem maradnak meg, amíg meg nem hívja a megfelelő SavePropertiesAsync metódust (például MusicProperties.SavePropertiesAsync). Akkor kell véglegesítenie a módosításokat, ha az elem elveszíti a fókuszt, mert ez a kijelölés alaphelyzetbe állítását váltja ki.
Vegye figyelembe, hogy az ezzel a technikával végzett kétirányú kötés csak indexelt helyeken működik, például a Zene szolgáltatással. A FolderInformation.GetIndexedStateAsync metódus meghívásával meghatározhatja, hogy egy hely indexelve van-e.
Vegye figyelembe azt is, hogy a virtualizált vektorok null értéket adhatnak vissza egyes elemekhez, mielőtt feltöltené az értéküket. Például a virtualizált vektorhoz kötött listavezérlő SelectedItem értékének használata vagy a SelectedIndex használata előtt érdemes ellenőriznie a null értéket.
Kötés kulcs szerint csoportosított adatokhoz
Ha egy egyszerű elemgyűjteményt (például könyveket egy BookSku osztály jelöl), és az elemeket kulcsként egy közös tulajdonság (például BookSku.AuthorName tulajdonság) használatával csoportosítja, akkor az eredményt csoportosított adatoknak nevezzük. Ha csoportosítja az adatokat, az már nem egy egybesimított gyűjtemény. A csoportosított adatok csoportobjektumok gyűjteményei, ahol minden csoportobjektum rendelkezik
- kulcs, és
- olyan elemek gyűjteménye, amelyek tulajdonsága megegyezik a kulcssal.
A könyvek példájának ismételt szemléltetéséhez a könyvek szerzőnév szerinti csoportosításának eredménye olyan szerzői névcsoportok gyűjteményét eredményezi, ahol az egyes csoportok
- egy kulcs, amely egy szerző neve, és
- a BookSkugyűjteményét, amelynek AuthorName tulajdonsága megegyezik a csoport kulcsával.
A gyűjtemények megjelenítéséhez általában közvetlenül egy gyűjteményt visszaadó tulajdonsághoz köti egy elemvezérlő ItemsSource elemforrását (például ListView vagy GridView). Ha ez egy egyszerű elemgyűjtemény, akkor semmi különlegeset nem kell tennie. Ha azonban csoportobjektumok gyűjteménye (mint a csoportosított adatokhoz való kötéskor), akkor szüksége lesz egy collectionViewSource nevű köztes objektum szolgáltatásaira, amely az elemek vezérlője és a kötési forrás között helyezkedik el. A CollectionViewSource-t ahhoz a tulajdonsághoz köti, amely csoportosított adatokat ad vissza, és az elemvezérlőt a CollectionViewSource-hoz köti. A CollectionViewSource további érték hozzáadása az, hogy nyomon követi az aktuális elemet, így több elem vezérlését is szinkronizálhatja úgy, hogy mindet ugyanarra a CollectionViewSource-ra köti. Az aktuális elemet programozott módon is elérheti a CollectionViewSource.View tulajdonság által visszaadott objektum ICollectionView.CurrentItem tulajdonságán keresztül.
A CollectionViewSource csoportosítási létesítményének aktiválásához állítsa az IsSourceGrouped értéket igaz értékre. Az, hogy az ItemsPath tulajdonságot is be kell-e állítania, pontosan attól függ, hogyan kell létrehoznia a csoportobjektumokat. A csoportobjektumok készítésének két módja van: az "is-a-group" minta és a "has-a-group" minta. Az "is-a-group" mintában a csoportobjektum gyűjteménytípusból (például T> lista<) származik, így a csoportobjektum valójában maga az elemek csoportja. Ezzel a mintával nem kell beállítania az ItemsPath-t. A "has-a-group" mintában a csoportobjektum egy vagy több gyűjteménytípusú tulajdonsággal rendelkezik (például a T> lista<), így a csoport "rendelkezik" elemcsoporttal egy tulajdonság formájában (vagy több elemcsoportban több tulajdonság formájában). Ezzel a mintával az ItemsPath értéket kell beállítania annak a tulajdonságnak a nevére, amely az elemek csoportját tartalmazza.
Az alábbi példa a "has-a-group" mintát szemlélteti. A laposztály egy ViewModel nevű tulajdonságot tartalmaz, amely a nézetmodell egy példányát adja vissza. A CollectionViewSource a nézetmodell Szerzők tulajdonságához kapcsolódik (a Szerzők csoportobjektumok gyűjteménye), és azt is megadja, hogy a csoportosított elemeket tartalmazó Author.BookSkus tulajdonság. Végül a GridView a CollectionViewSource-hoz van kötve, és definiálva van a csoportstílusa, hogy megjeleníthesse az elemeket csoportokban.
<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>
Az "is-a-group" mintát kétféleképpen valósíthatja meg. Ennek egyik módja a saját csoportosztály létrehozása. Az osztályt a T> listából< származtathatja (ahol a T az elemek típusa). Például: public class Author : List<BookSku>. A második módszer egy LINQ-kifejezés használata csoportobjektumok (és csoportosztályok) dinamikus létrehozásához a BookSku-elemek hasonló tulajdonságértékeiből. Ez a megközelítés – ha csak egy egyszerű lista áll fenn az elemek között, és menet közben csoportosítja őket – jellemzően egy olyan alkalmazás, amely egy felhőszolgáltatásból fér hozzá az adatokhoz. Rugalmasan csoportosíthatja a könyveket szerző vagy műfaj szerint (például) anélkül, hogy speciális csoportosztályokra, például a Szerzőre és a Műfajra lenne szüksége.
Az alábbi példa a LINQ használatával szemlélteti az "is-a-group" mintát. Ezúttal műfaj szerint csoportosítjuk a könyveket, és a csoportfejlécekben a műfaj neve látható. Ezt jelzi a "Kulcs" tulajdonság elérési útja a csoportkulcs értékére hivatkozva.
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;
}
}
Ne feledje, hogy a(z) {x:Bind} adatsablonokkal való használatakor x :DataType érték beállításával meg kell jelölni a kötés típusát. Ha a típus általános, akkor ezt nem fejezhetjük ki korrektúraként, ezért a csoportstílus fejlécsablonjában a {Binding} parancsot kell használnunk.
<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>
A SzemanticZoom vezérlő nagyszerű lehetőséget biztosít a felhasználók számára a csoportosított adatok megtekintésére és navigálására. A Bookstore2 mintaalkalmazás a SzemanticZoom használatát mutatja be. Ebben az alkalmazásban megtekintheti a szerzők szerint csoportosított könyvek listáját (a nagyított nézetet), vagy kicsinyítheti is a szerzők jumplistáját (a kicsinyített nézetet). A jump lista sokkal gyorsabb navigációt biztosít, mint a könyvek listájának görgetése. A nagyított és kicsinyített nézetek valójában ListView - vagy GridView-vezérlők , amelyek ugyanahhoz a CollectionViewSource-hoz vannak kötve.
Ha hierarchikus adatokhoz – például kategóriákon belüli alkategóriákhoz – kapcsolódik, a felhasználói felületen több elemvezérlővel is megjelenítheti a hierarchikus szinteket. Az egyik elem vezérlőelemben lévő kijelölés határozza meg a további elemvezérlők tartalmát. A listákat szinkronizálhatja úgy, hogy az egyes listákat a saját CollectionViewSource-hoz köti, és egy láncban köti össze a CollectionViewSource-példányokat . Ezt master/details (vagy list/details) nézetnek nevezzük. További információ : Hierarchikus adatokhoz való kötés és master/details nézet létrehozása.
Adatkötési problémák diagnosztizálása és hibakeresése
A kötési korrektúra tartalmazza a tulajdonságok nevét (c# esetén pedig néha mezőket és metódusokat). Egy tulajdonság átnevezésekor tehát módosítania kell az arra hivatkozó kötéseket is. Ha elfelejti ezt megtenni, az egy adatkötési hiba tipikus példájához vezet, és az alkalmazás vagy nem fordít le, vagy nem fog megfelelően futni.
A(z) {x:Bind} és {Binding} által létrehozott kötésobjektumok funkcionálisan egyenértékűek. A(z) {x:Bind} azonban rendelkezik a kötés forrásának típusadataival, és fordítási időben hozza létre a forráskódot. A(z) {x:Bind} használatával ugyanazt a problémaészlelést kapja, mint a kód többi részében. Ez magában foglalja a kötési kifejezések fordítási idejének ellenőrzését, valamint a hibakeresést a lap részleges osztályaként létrehozott forráskód töréspontjainak beállításával. Ezek az osztályok megtalálhatók a mappában lévő fájlokban obj , például (c#) <view name>.g.csnéven. Ha problémát tapasztal egy kötéssel kapcsolatban, kapcsolja be a Nem kezelt kivételek megszakítása funkciót a Microsoft Visual Studio hibakeresőjében. A hibakereső ekkor megszakítja a végrehajtást, majd hibakeresést végezhet. A(z) {x:Bind} által létrehozott kód ugyanazt a mintát követi a kötési forráscsomópontok gráfjának minden részén, és a Hívásverem ablakban található információk segítségével meghatározhatja a problémához vezető hívások sorrendjét.
A(z) {Binding} nem rendelkezik a kötés forrásának típusadataival. Ha azonban az alkalmazást a csatolt hibakeresővel futtatja, a kötési hibák megjelennek a Visual Studio Kimenet ablakában.
Kötések létrehozása kódban
Jegyzet Ez a szakasz csak a(z) {Binding}-ra vonatkozik, mert nem hozhat létre {x:Bind} kötéseket a kódban. A(z) {x:Bind} néhány előnye azonban elérhető a DependencyObject.RegisterPropertyChangedCallback szolgáltatással, amely lehetővé teszi a változásértesítések regisztrálását bármely függőségi tulajdonságon.
A felhasználói felület elemeit XAML helyett eljárási kóddal is csatlakoztathatja az adatokhoz. Ehhez hozzon létre egy új kötésobjektumot , állítsa be a megfelelő tulajdonságokat, majd hívja meg a FrameworkElement.SetBinding vagy a BindingOperations.SetBinding parancsot. A kötések programozott létrehozása akkor hasznos, ha futásidőben szeretné kiválasztani a kötéstulajdonság-értékeket, vagy egyetlen kötést szeretne megosztani több vezérlő között. Vegye figyelembe azonban, hogy a SetBinding meghívása után nem módosíthatja a kötéstulajdonság-értékeket.
Az alábbi példa bemutatja, hogyan implementálhat egy kötést a kódban.
<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)
{x:Bind} és {Binding} funkció összehasonlítása
| Tulajdonság | {x:Bind} és {Binding} | Jegyzetek |
|---|---|---|
| Az elérési út az alapértelmezett tulajdonság | {x:Bind a.b.c}- {Binding a.b.c} |
|
| Elérési út tulajdonság | {x:Bind Path=a.b.c}- {Binding Path=a.b.c} |
Az x:Kötésben az elérési út alapértelmezés szerint a lapon gyökerezik, nem a DataContextben. |
| Indexelő | {x:Bind Groups[2].Title}- {Binding Groups[2].Title} |
Kötések a gyűjtemény megadott eleméhez. Csak egész számalapú indexek támogatottak. |
| Csatolt tulajdonságok | {x:Bind Button22.(Grid.Row)}- {Binding Button22.(Grid.Row)} |
A csatolt tulajdonságok zárójelek használatával vannak megadva. Ha a tulajdonság nem XAML-névtérben van deklarálva, akkor az előtagot xml névtérrel kell ellátni, amelyet a dokumentum elején lévő kódnévtérre kell leképezni. |
| Öntés | {x:Bind groups[0].(data:SampleDataGroup.Title)}- A(z) {Binding} nem szükséges. |
A leadások zárójelek használatával vannak megadva. Ha a tulajdonság nem XAML-névtérben van deklarálva, akkor az előtagot xml névtérrel kell ellátni, amelyet a dokumentum elején lévő kódnévtérre kell leképezni. |
| Konverter | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}}- {Binding IsShown, Converter={StaticResource BoolToVisibility}} |
A konvertereket a Page/ResourceDictionary gyökerénél vagy az App.xaml-ben kell deklarálni. |
| ConverterParameter, ConverterLanguage | {x:Bind IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr}- {Binding IsShown, Converter={StaticResource BoolToVisibility}, ConverterParameter=One, ConverterLanguage=fr-fr} |
A konvertereket a Page/ResourceDictionary gyökerénél vagy az App.xaml-ben kell deklarálni. |
| TargetNullValue | {x:Bind Name, TargetNullValue=0}- {Binding Name, TargetNullValue=0} |
Akkor használatos, ha a kötési kifejezés levele null. Sztringértékhez használjon egyetlen idézőjelet. |
| FallbackValue | {x:Bind Name, FallbackValue='empty'}- {Binding Name, FallbackValue='empty'} |
Akkor használatos, ha a kötés elérési útjának bármely része (a levél kivételével) null értékű. |
| Elemnév | {x:Bind slider1.Value}- {Binding Value, ElementName=slider1} |
A(z) {x:Bind} használatával egy mezőhöz van kötése; Az elérési út alapértelmezés szerint az oldalon gyökerezik, így bármely elnevezett elem elérhető a mezőn keresztül. |
| RelativeSource: Self | <Rectangle x:Name="rect1" Width="200" Height="{x:Bind rect1.Width}" ... />- <Rectangle Width="200" Height="{Binding Width, RelativeSource={RelativeSource Self}}" ... /> |
{x:Bind} használatával nevezze el az elemet, és használja a nevét az Elérési úton. |
| RelativeSource: TemplatedParent | Nem szükséges {x:Bind} esetén - {Binding <path>, RelativeSource={RelativeSource TemplatedParent}} |
A ControlTemplate {x:Bind} TargetType elemével a sablon szülőhöz való kötést jelzi. A(z) {Binding} normál sablonkötése a legtöbb használathoz használható vezérlősablonokban. De használja a TemplatedParentet, ahol konvertert vagy kétirányú kötést kell használnia.< |
| Forrás | Nem szükséges {x:Bind} esetén - <ListView ItemsSource="{Binding Orders, Source={StaticResource MyData}}"/> |
{x:Bind} esetén közvetlenül használhatja az elnevezett elemet, használhat tulajdonságot vagy statikus elérési utat. |
| Üzemmód | {x:Bind Name, Mode=OneWay}- {Binding Name, Mode=TwoWay} |
A mód lehet OneTime, OneWay vagy TwoWay. {x:Bind} alapértelmezés szerint OneTime; A(z) {Binding} alapértelmezés szerint a OneWay. |
| UpdateSourceTrigger | {x:Bind Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}- {Binding UpdateSourceTrigger=PropertyChanged} |
Az UpdateSourceTrigger lehet alapértelmezett, LostFocus vagy PropertyChanged. A(z) {x:Bind} nem támogatja az UpdateSourceTrigger=Explicit fájlt. {x:Bind} a TextBox.Text kivételével minden esetben a PropertyChanged viselkedést használja, ahol LostFocus viselkedést használ. |