Adatkötés áttekintése (WPF .NET)
A Windows Presentation Foundation (WPF) adatkötése egyszerű és konzisztens módot biztosít az alkalmazások számára az adatok bemutatására és kezelésére. Az elemek különböző típusú adatforrásokból származó adatokhoz köthetők .NET-objektumok és XML-objektumok formájában. Az olyan ContentControl, mint a Button és bármely ItemsControl, például ListBox és ListView, beépített funkciókkal rendelkeznek, amelyek lehetővé teszik az önálló adatelemek vagy adatelemek gyűjteményeinek rugalmas stílusát. A rendezési, szűrési és csoportnézetek az adatok tetején hozhatók létre.
A WPF-ben az adatkötés számos előnnyel rendelkezik a hagyományos modellekkel szemben, beleértve a tulajdonságok széles skálája által nyújtott adatkötést, az adatok rugalmas felhasználói felületi ábrázolását, valamint az üzleti logika és a felhasználói felület tiszta elkülönítését.
Ez a cikk először a WPF-adatkötés alapvető fogalmait ismerteti, majd ismerteti a Binding osztály használatát és az adatkötés egyéb funkcióit.
Mi az adatkötés?
Az adatkötés az az eljárás, amely kapcsolatot hoz létre az alkalmazás felhasználói felülete és a megjelenített adatok között. Ha a kötés megfelelő beállításokkal rendelkezik, és az adatok a megfelelő értesítéseket biztosítják, az adatok értékének módosításakor az adatokhoz kötött elemek automatikusan tükrözik a változásokat. Az adatkötés azt is jelentheti, hogy ha egy elem adatainak külső megjelenítése megváltozik, akkor a mögöttes adatok automatikusan frissíthetők a változásnak megfelelően. Ha például a felhasználó egy TextBox
elemben szerkessze az értéket, a rendszer automatikusan frissíti a mögöttes adatértéket a változásnak megfelelően.
Az adatkötések tipikus használata a kiszolgálói vagy helyi konfigurációs adatok űrlapokba vagy más felhasználói felületi vezérlőkbe való elhelyezése. A WPF-ben ez a fogalom kibővül, így számos tulajdonságot köthet különböző típusú adatforrásokhoz. A WPF-ben az elemek függőségi tulajdonságai .NET-objektumokhoz (beleértve ADO.NET webszolgáltatásokhoz és webtulajdonságokhoz társított objektumokat) és XML-adatokhoz köthetők.
Alapvető adatkötési fogalmak
Függetlenül attól, hogy milyen elemet köt, és milyen jellegű az adatforrás, minden kötés mindig az alábbi ábrán látható modellt követi.
Ahogy az ábra is mutatja, az adatkötés lényegében a kötési cél és a kötési forrás közötti híd. Az ábra az alábbi alapvető WPF-adatkötési fogalmakat mutatja be:
Általában minden kötés négy összetevőből áll:
- Hozzárendelési célobjektum.
- Céltulajdonság.
- Kötési forrás.
- A használni kívánt kötésforrás értékének elérési útja.
Ha például egy
TextBox
tartalmát aEmployee.Name
tulajdonsághoz kötötte, a kötést az alábbi táblázathoz hasonlóan állíthatja be:Beállítás Érték Cél TextBox Céltulajdonság Text Forrásobjektum Employee
Forrásobjektum értékének elérési útja Name
A céltulajdonságnak függőségi tulajdonságnak kell lennie.
A legtöbb UIElement tulajdonság függőségi tulajdonságok, és a legtöbb függőségi tulajdonság, kivéve az írásvédett tulajdonságokat, alapértelmezés szerint támogatja az adatkötést. Csak a DependencyObject származó típusok definiálhatnak függőségi tulajdonságokat. Minden UIElement típus
DependencyObject
származik.A kötési források nem korlátozódnak az egyéni .NET-objektumokra.
Bár az ábrán nem látható, meg kell jegyezni, hogy a kötés forrásobjektuma nem korlátozódik egyéni .NET-objektumra. A WPF-adatkötés .NET-objektumok, XML- és akár XAML-elemobjektumok formájában támogatja az adatokat. Néhány példa megjelenítéséhez a kötés forrása lehet egy UIElement, egy listaobjektum, egy ADO.NET vagy Web Services-objektum, vagy egy XML-adatokat tartalmazó XmlNode. További információ: Kötésforrások áttekintése.
Fontos megjegyezni, hogy a kötés létrehozásakor a kötési cél van hozzákapcsolva egy kötésforráshoz. Ha például adatkötéssel jelenít meg néhány mögöttes XML-adatot egy ListBox-ban, akkor a ListBox
-et az XML-adatokhoz köti.
Kötés létrehozásához használja a Binding objektumot. A cikk további része az Binding
objektum tulajdonságaival és használatával kapcsolatos számos fogalmat és néhányat ismerteti.
Adatkörnyezet
Ha az adatkötést a XAML-elemekben deklarálják, az adatkötést a közvetlen DataContext tulajdonságuk áttekintésével oldják fel. Az adatkörnyezet tipikusan a kötési forrásobjektum, a kötési forrásérték elérési útjának kiértékelése során. Ezt a viselkedést felülbírálhatja a kötésben, és beállíthat egy adott kötésforrás-objektumot értéket. Ha a kötést üzemeltető objektum DataContext
tulajdonsága nincs beállítva, a szülőelem DataContext
tulajdonsága az XAML objektumfa gyökeréig be van jelölve, és így tovább. Röviden: a kötés feloldásához használt adatkörnyezet öröklődik a szülőtől, kivéve, ha explicit módon van beállítva az objektumon.
A kötések konfigurálhatók úgy, hogy egy adott objektummal oldódjanak fel, ellentétben azzal, amikor az adatkörnyezetet használják a kötés feloldására. A forrásobjektum közvetlen megadása akkor használatos, ha például egy objektum előtérszínét egy másik objektum háttérszínéhez köti. Az adatkörnyezetre nincs szükség, mivel a kötés feloldva van a két objektum között. Ezzel szemben az adott forrásobjektumokhoz nem kötött kötések adatkörnyezet-felbontást használnak.
Amikor a DataContext
tulajdonság megváltozik, a rendszer újraértékesíti az adatkörnyezet által érintett összes kötést.
Az adatfolyam iránya
Ahogy az előző ábrán látható nyíl jelzi, a kötés adatfolyama a kötési céltól a kötésforrásig (például a forrásérték megváltozik, amikor egy felhasználó szerkeszti egy TextBox
értékét) és/vagy a kötési forrásból a kötési célhoz (például a TextBox
tartalma frissül a kötés forrásának változásaival), ha a kötési forrás megfelelő értesítéseket biztosít.
Előfordulhat, hogy azt szeretné, hogy az alkalmazás lehetővé tegye a felhasználók számára az adatok módosítását és a forrásobjektumba való visszaterjesztését. Vagy előfordulhat, hogy nem szeretné engedélyezni a felhasználók számára a forrásadatok frissítését. Az adatok áramlását a Binding.Modebeállításával szabályozhatja.
Ez az ábra az adatfolyamok különböző típusait mutatja be:
OneWay kötés hatására a forrástulajdonság módosításai automatikusan frissítik a céltulajdonságot, de a céltulajdonság módosításait a rendszer nem propagálja vissza a forrástulajdonságra. Ez a kötéstípus akkor megfelelő, ha a kötött vezérlőelem implicit módon írásvédett. Előfordulhat például, hogy egy forráshoz, például egy tőzsdei ketyegőhöz kötődik, vagy a céltulajdonság nem rendelkezik olyan vezérlőfelülettel, amellyel módosításokat hajthat végre, például egy tábla adathoz kötött háttérszínét. Ha nincs szükség a céltulajdonság változásainak monitorozására, a OneWay kötési mód használata elkerüli a TwoWay kötési mód többletterhelését.
TwoWay kötés hatására a forrástulajdonság vagy a céltulajdonság módosítása automatikusan frissíti a másikat. Ez a kötéstípus szerkeszthető űrlapokhoz vagy más teljesen interaktív felhasználói felületi forgatókönyvekhez megfelelő. A legtöbb tulajdonság alapértelmezés szerint a OneWay kötést használja, de bizonyos függőségi tulajdonságok, például a felhasználó által szerkeszthető vezérlők tulajdonságai, mint a TextBox.Text és a Jelölőnégyzet.IsChecked, alapértelmezés szerint a és TwoWay kötést alkalmazzák.
A programozott megközelítés, amellyel meghatározható, hogy egy függőségi tulajdonság alapértelmezés szerint egyirányú vagy kétirányú kötésű, az a tulajdonság metaadatainak lekérése DependencyProperty.GetMetadata-ra. Ennek a metódusnak a visszatérési típusa PropertyMetadata, amely nem tartalmaz metaadatokat a kötésről. Ha azonban ez a típus átalakítható-e a származtatott FrameworkPropertyMetadatatípusra, akkor a FrameworkPropertyMetadata.BindsTwoWayByDefault tulajdonság logikai értéke ellenőrizhető. Az alábbi példakód bemutatja a TextBox.Text tulajdonság metaadatainak lekérését:
public static void PrintMetadata() { // Get the metadata for the property PropertyMetadata metadata = TextBox.TextProperty.GetMetadata(typeof(TextBox)); // Check if metadata type is FrameworkPropertyMetadata if (metadata is FrameworkPropertyMetadata frameworkMetadata) { System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:"); System.Diagnostics.Debug.WriteLine($" BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}"); System.Diagnostics.Debug.WriteLine($" IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}"); System.Diagnostics.Debug.WriteLine($" AffectsArrange: {frameworkMetadata.AffectsArrange}"); System.Diagnostics.Debug.WriteLine($" AffectsMeasure: {frameworkMetadata.AffectsMeasure}"); System.Diagnostics.Debug.WriteLine($" AffectsRender: {frameworkMetadata.AffectsRender}"); System.Diagnostics.Debug.WriteLine($" Inherits: {frameworkMetadata.Inherits}"); } /* Displays: * * TextBox.Text property metadata: * BindsTwoWayByDefault: True * IsDataBindingAllowed: True * AffectsArrange: False * AffectsMeasure: False * AffectsRender: False * Inherits: False */ }
Public Shared Sub PrintMetadata() Dim metadata As PropertyMetadata = TextBox.TextProperty.GetMetadata(GetType(TextBox)) Dim frameworkMetadata As FrameworkPropertyMetadata = TryCast(metadata, FrameworkPropertyMetadata) If frameworkMetadata IsNot Nothing Then System.Diagnostics.Debug.WriteLine($"TextBox.Text property metadata:") System.Diagnostics.Debug.WriteLine($" BindsTwoWayByDefault: {frameworkMetadata.BindsTwoWayByDefault}") System.Diagnostics.Debug.WriteLine($" IsDataBindingAllowed: {frameworkMetadata.IsDataBindingAllowed}") System.Diagnostics.Debug.WriteLine($" AffectsArrange: {frameworkMetadata.AffectsArrange}") System.Diagnostics.Debug.WriteLine($" AffectsMeasure: {frameworkMetadata.AffectsMeasure}") System.Diagnostics.Debug.WriteLine($" AffectsRender: {frameworkMetadata.AffectsRender}") System.Diagnostics.Debug.WriteLine($" Inherits: {frameworkMetadata.Inherits}") ' Displays: ' ' TextBox.Text property metadata: ' BindsTwoWayByDefault: True ' IsDataBindingAllowed: True ' AffectsArrange: False ' AffectsMeasure: False ' AffectsRender: False ' Inherits: False End If End Sub
OneWayToSource OneWay kötés fordítottja; a céltulajdonság módosításakor frissíti a forrástulajdonságot. Az egyik példaforgatókönyv az, ha csak a felhasználói felületről kell újraértékelnie a forrásértéket.
Az ábrán nem látható OneTime kötés, amely miatt a forrástulajdonság inicializálja a céltulajdonságot, de nem propagálja a későbbi módosításokat. Ha az adatkörnyezet megváltozik, vagy az adatkörnyezet objektuma megváltozik, a módosítás nem tükröződik a céltulajdonságban. Ez a kötéstípus akkor megfelelő, ha az aktuális állapot pillanatképe megfelelő, vagy az adatok valóban statikusak. Ez a kötéstípus akkor is hasznos, ha egy forrástulajdonságból származó értékkel szeretné inicializálni a céltulajdonságot, és az adatkörnyezet nem ismert előre. Ez a mód lényegében a OneWay kötés egyszerűbb formája, amely jobb teljesítményt nyújt olyan esetekben, amikor a forrásérték nem változik.
A forrásváltozások észleléséhez (OneWay és TwoWay kötésekre alkalmazható) a forrásnak megfelelő tulajdonságváltozás-értesítési mechanizmust kell implementálnia, például INotifyPropertyChanged. A INotifyPropertyChanged megvalósítására példaként tekintse meg a : Tulajdonságváltozás-értesítés (.NET-keretrendszer) implementálása című témakört.
A Binding.Mode tulajdonság további információt nyújt a kötési módokról, és egy példa a kötés irányának megadására.
Mi aktiválja a forrásfrissítéseket?
Azok a kötések, amelyek TwoWay vagy OneWayToSource figyelik a céltulajdonság módosításait, és propagálják azokat a forrásra, ezt forrásfrissítésnek nevezik. Módosíthatja például egy Szövegdoboz szövegét a mögöttes forrásérték módosításához.
A forrásérték azonban frissül a szöveg szerkesztése közben, vagy a szöveg szerkesztése után, amikor a vezérlő elveszíti a fókuszt? A Binding.UpdateSourceTrigger tulajdonság határozza meg, hogy mi váltja ki a forrás frissítését. A következő ábrán a jobbra mutató nyilak pontjai szemléltetik a Binding.UpdateSourceTrigger tulajdonság szerepét.
Ha a UpdateSourceTrigger
érték UpdateSourceTrigger.PropertyChanged, akkor a céltulajdonság változásakor a TwoWay vagy a OneWayToSource kötések jobb nyílával mutatott érték frissül. Ha azonban a UpdateSourceTrigger
érték LostFocus, akkor az érték csak akkor frissül az új értékkel, ha a céltulajdonság elveszíti a fókuszt.
A Mode tulajdonsághoz hasonlóan a különböző függőségi tulajdonságok eltérő alapértelmezett UpdateSourceTrigger értékekkel rendelkeznek. A legtöbb függőségi tulajdonság alapértelmezett értéke PropertyChanged, ami miatt a forrástulajdonság értéke azonnal megváltozik a céltulajdonság módosításakor. Az azonnali módosítások CheckBox és más egyszerű vezérlők esetén is jól használhatók. A szövegmezők esetében azonban az összes billentyűleütés utáni frissítés csökkentheti a teljesítményt, és tagadja a felhasználótól a szokásos lehetőséget, hogy visszaterelje és javítsa a gépelési hibákat, mielőtt véglegesíti az új értéket. A TextBox.Text
tulajdonság például alapértelmezés szerint a LostFocusUpdateSourceTrigger
értéke, ami miatt a forrásérték csak akkor változik, ha a vezérlőelem elveszíti a fókuszt, és nem a TextBox.Text
tulajdonság módosításakor. A függőségi tulajdonság alapértelmezett értékének megkereséséről a UpdateSourceTrigger tulajdonságlapján olvashat.
Az alábbi táblázat egy példaforgatókönyvet biztosít minden UpdateSourceTrigger értékhez, példaként a TextBox használatával.
UpdateSourceTrigger érték | A forrásérték frissítésekor | Példaforgatókönyv a TextBoxhoz |
---|---|---|
LostFocus (alapértelmezett TextBox.Text) |
Amikor a Szövegdoboz vezérlő elveszíti a fókuszt. | Az érvényesítési logikához társított szövegmező (lásd adatérvényesítési alább). |
PropertyChanged |
Amikor gépelsz a(z) TextBox-ba. | TextBox-vezérlők a csevegőszoba ablakában. |
Explicit |
Amikor az alkalmazás meghívja UpdateSource. | A TextBox-vezérlők szerkeszthető formában (csak akkor frissítik a forrásértékeket, ha a felhasználó lenyomja a Küldés gombot). |
Példaként lásd: Útmutató: Hogyan szabályozható, hogy a szövegdoboz szövege mikor frissíti a forrást (.NET-keretrendszer).
Példa adatkötésre
Az adatkötésre példaként tekintse meg az alábbi alkalmazás felhasználói felületét az Adatkötési bemutató, amely megjeleníti az árverési elemek listáját.
Az alkalmazás az adatkötés alábbi funkcióit mutatja be:
A ListBox tartalma AuctionItem objektumok gyűjteményéhez van kötve. Az AuctionItem objektum olyan tulajdonságokkal rendelkezik, mint Leírás, StartPrice, StartDate, Kategóriaés SpecialFeatures.
A
ListBox
megjelenített adatok (AuctionItem objektumok) sablonosak, így a leírás és az aktuális ár minden elemnél megjelenik. A sablon egy DataTemplatehasználatával jön létre. Emellett az egyes elemek megjelenése az éppen megjelenített AuctionItemSpecialFeatures értékétől függ. Ha a SpecialFeaturesAuctionItem értéke Szín, az elem kék szegélyrel rendelkezik. Ha az érték Kiemelő, az elem narancssárga szegélyt és csillagot kapott. A Data Templating szakasz az adatsablonozásról nyújt tájékoztatást.A felhasználó a megadott
CheckBoxes
használatával csoportosíthatja, szűrheti vagy rendezheti az adatokat. A fenti képen a csoportosítás kategória szerint és a rendezés kategória és dátum szerintCheckBoxes
van kiválasztva. Előfordulhat, hogy észrevette, hogy az adatok a termék kategóriája alapján vannak csoportosítva, és a kategória neve betűrendben van. A képről nehéz észrevenni, de az elemeket az egyes kategóriák kezdő dátuma szerint is rendezi. A gyűjteménynézethasználatával történik a rendezés. A gyűjteményekhez való kötés szakasz a gyűjteménynézeteket ismerteti.Amikor a felhasználó kiválaszt egy elemet, a ContentControl megjeleníti a kijelölt elem részleteit. Ezt az élményt az úgynevezett Master-detail forgatókönyvnek nevezzük. A master-detail forgatókönyv szakasza információt nyújt az ilyen típusú kötésekkel kapcsolatban.
A StartDate tulajdonság típusa DateTime, amely az ezredmásodpercig eltelt időt tartalmazó dátumot adja vissza. Ebben az alkalmazásban egy egyéni konvertert használtunk, hogy egy rövidebb dátumsztring jelenjen meg. Az adatkonvertálási szakasz információkat nyújt a konverterekről.
Amikor a felhasználó a Termék hozzáadása gombot választja, megjelenik az alábbi űrlap.
A felhasználó szerkesztheti az űrlap mezőit, megtekintheti a terméklista előnézetét a rövid vagy részletes előnézeti ablaktáblák használatával, és kiválaszthatja a Submit
az új terméklista hozzáadásához. A meglévő csoportosítási, szűrési és rendezési beállítások az új bejegyzésre vonatkoznak. Ebben az esetben a fenti képen megadott elem második elemként jelenik meg a Számítógép kategóriában.
Nincs látható a képen az a validációs logika, amely a Kezdő dátumTextBox-hez van társítva. Ha a felhasználó érvénytelen dátumot (érvénytelen formázást vagy múltbeli dátumot) ad meg, a felhasználó értesítést kap egy ToolTip és egy piros felkiáltójellel a TextBoxmellett. Az adatérvényesítési szakasz az érvényesítési logika létrehozását ismerteti.
Mielőtt áttekintenénk a fent vázolt adatkötés különböző funkcióit, először azokat az alapvető fogalmakat ismertetjük, amelyek elengedhetetlenek a WPF-adatkötés megértéséhez.
Kötés létrehozása
Az előző szakaszokban tárgyalt fogalmak újragondolásához egy kötést kell létrehoznia a Binding objektummal, és minden kötés általában négy összetevőből áll: egy kötési célból, egy céltulajdonságból, egy kötési forrásból és a használandó forrásérték elérési útból. Ez a szakasz a kötések beállítását ismerteti.
A kötési források az elem aktív DataContext-hoz vannak kötve. Az elemek automatikusan öröklik a DataContext
, ha nem definiáltak explicit módon egyet.
Vegye figyelembe az alábbi példát, amelyben a kötés forrásobjektuma egy MyData nevű osztály, amely a SDKSample névtérben van definiálva. Bemutató célokra a MyData rendelkezik egy ColorName nevű sztringtulajdonsággal, amelynek értéke "Piros". Így ez a példa egy piros háttérrel rendelkező gombot hoz létre.
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<DockPanel.DataContext>
<Binding Source="{StaticResource myDataSource}"/>
</DockPanel.DataContext>
<Button Background="{Binding Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
A kötési deklaráció szintaxisáról és a kötések kódban való beállításának módjáról további információt Kötésdeklarációk áttekintésecímű témakörben talál.
Ha ezt a példát az alapdiagramra alkalmazzuk, az eredményként kapott ábra a következőhöz hasonlóan néz ki. Ez az ábra egy OneWay kötést ír le, mert a Háttér tulajdonság alapértelmezés szerint támogatja OneWay kötést.
Felmerülhet a kérdés, hogy ez a kötés miért működik annak ellenére, hogy a ColorName tulajdonság string típusú, míg a Background tulajdonság Brushtípusú. Ez a kötés alapértelmezett típuskonvertálást használ, amelyet az Adatkonvertálás szakaszban tárgyalunk.
A kötés forrásának megadása
Figyelje meg, hogy az előző példában a kötés forrása a DockPanel.DataContext tulajdonság beállításával van megadva. A Button ezután örökli a DataContext értéket a DockPanel-ből, amely a szülőeleme. Megismétlendő, hogy a kötés forrásobjektuma a kötés négy szükséges összetevőjének egyike. Így a kötés forrásobjektumának megadása nélkül a kötés nem tenne semmit.
A kötés forrásobjektumát többféleképpen is megadhatja. A szülőelem DataContext tulajdonságának használata akkor hasznos, ha több tulajdonságot köt ugyanahhoz a forráshoz. Néha azonban célszerűbb lehet meghatározni a kötés forrását az egyes kötési deklarációkon. Az előző példában a DataContext tulajdonság használata helyett úgy adhatja meg a kötési forrást, hogy közvetlenül a gomb kötésdeklarációjára állítja be a Binding.Source tulajdonságot, ahogyan az alábbi példában is látható.
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
A DataContext tulajdonság közvetlen beállításán kívül a DataContext értéket örökölheti egy elődtől (például az első példában szereplő gombtól), és explicit módon megadhatja a kötés forrását a kötés Binding.Source tulajdonságának beállításával (például az utolsó példa gomb) a Binding.ElementName tulajdonság vagy a Binding.RelativeSource tulajdonság használatával is megadhatja a kötés forrását. A ElementName tulajdonság akkor hasznos, ha az alkalmazás más elemeihez kötődik, például ha csúszkával állítja be a gomb szélességét. A RelativeSource tulajdonság akkor hasznos, ha a kötés egy ControlTemplate vagy egy Stylevan megadva. További információ: Kötésforrások áttekintése.
Az érték elérési útjának megadása
Ha a kötés forrása objektum, a Binding.Path tulajdonság használatával adja meg a kötéshez használni kívánt értéket. Ha XML-adatokhoz köti, a Binding.XPath tulajdonság használatával adja meg az értéket. Bizonyos esetekben a Path tulajdonság akkor is használható, ha az adatok XML-alapúak. Ha például egy visszaadott XmlNode Név tulajdonságához szeretne hozzáférni (egy XPath-lekérdezés eredményeként), a XPath tulajdonság mellett a Path tulajdonságot is használnia kell.
További információ: Path és XPath tulajdonságok.
Bár hangsúlyoztuk, hogy a használni kívánt értékre vonatkozó Path a kötés négy szükséges összetevőjének egyike, azokban a forgatókönyvekben, amelyeket egy teljes objektumhoz szeretne kötni, a használni kívánt érték megegyezik a kötés forrásobjektumával. Ilyen esetekben ajánlott nem megadni a Path-t. Vegye figyelembe az alábbi példát.
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"/>
A fenti példa az üres kötés szintaxisát használja: {Binding}. Ebben az esetben a ListBox egy szülő DockPanel-elemtől örökli a DataContextet (ebben a példában nem látható). Ha az elérési út nincs megadva, az alapértelmezett érték a teljes objektumhoz való kötés. Más szóval ebben a példában az elérési út kimaradt, mert a ItemsSource tulajdonságot a teljes objektumhoz kötjük. (Részletes ismertetésért tekintse meg a a gyűjteményekhez való kötésről szóló szakaszt.)
A gyűjteményhez való kötésen kívül ez a forgatókönyv akkor is hasznos, ha egy objektum egyetlen tulajdonsága helyett egy teljes objektumhoz szeretne kapcsolódni. Ha például a forrásobjektum Stringtípusú, akkor egyszerűen csak a karakterlánchoz kell kapcsolnia. Egy másik gyakori forgatókönyv az, amikor egy elemet több tulajdonsággal rendelkező objektumhoz szeretne kötni.
Előfordulhat, hogy egyéni logikát kell alkalmaznia, hogy az adatok értelmesek legyenek a kapcsolt céltulajdonság számára. Előfordulhat, hogy az egyéni logika egyéni konverter formájában jelenik meg, ha az alapértelmezett típuskonvertálás nem létezik. A konverterekkel kapcsolatos információkért lásd a adatkonvertálás.
Kötés és kötésexpresszió
Mielőtt megismerkedik az adatkötés egyéb funkcióival és használatával, érdemes bevezetni a BindingExpression osztályt. Ahogy az előző szakaszokban is láthatta, a Binding osztály a kötés deklarálásának magas szintű osztálya; Számos olyan tulajdonságot biztosít, amelyek lehetővé teszik a kötések jellemzőinek megadását. A kapcsolódó osztály ( BindingExpression) az a mögöttes objektum, amely fenntartja a kapcsolatot a forrás és a cél között. A kötések tartalmazzák a több kötési kifejezés között megosztható összes információt. A BindingExpression olyan példánykifejezés, amely nem osztható meg, és tartalmazza a Bindingösszes példányinformációját.
Az alábbi példában az myDataObject
a MyData
osztály egy példánya, myBinding
a forrás Binding objektum, MyData
pedig egy definiált osztály, amely egy ColorName
nevű sztringtulajdonságot tartalmaz. Ez a példa a myText
szöveges tartalmát, amely a TextBlockegy példánya, hozzákapcsolja a ColorName
-höz.
// Make a new source
var myDataObject = new MyData();
var myBinding = new Binding("ColorName")
{
Source = myDataObject
};
// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
' Make a New source
Dim myDataObject As New MyData
Dim myBinding As New Binding("ColorName")
myBinding.Source = myDataObject
' Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding)
Ugyanezt a myBinding objektumot használhatja más kötések létrehozásához. Használhatja például a myBinding objektumot, hogy egy jelölőnégyzet szöveges tartalmát a ColorName-hez kösse. Ebben a forgatókönyvben két BindingExpression példány osztozik a myBinding objektumon.
Egy BindingExpression objektum visszaadása GetBindingExpression adathoz kötött objektumon való meghívásával történik. Az alábbi cikkek a BindingExpression osztály néhány használatát mutatják be:
- Kötésobjektum lekérése kötött céltulajdonságból (.NET-keretrendszer)
- Amikor a Szövegdoboz vezérli a szöveg forrásfrissítését (.NET-keretrendszer)
Adatkonvertálás
A Kötés létrehozása szakaszban a gomb piros, mivel a Background tulajdonság egy "Red" értékkel rendelkező karakterlánc-tulajdonsághoz van kötve. Ez a sztringérték azért működik, mert a Brush típuson egy típuskonverter található a sztring értékének Brushvaló konvertálásához.
Az adatok hozzáadása a Kötés létrehozása szakaszban szereplő ábrához így néz ki.
Mi a teendő azonban, ha a kötés forrásobjektumának sztring típusú tulajdonsága helyett szín típusú tulajdonsága Colorvan? Ebben az esetben a kötés működéséhez először a Szín tulajdonság értékét kell a Background tulajdonság által elfogadott értékké alakítania. Az IValueConverter felület implementálásával létre kell hoznia egy egyéni konvertert, ahogyan az alábbi példában is látható.
[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Color color = (Color)value;
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
Dim color As Color = CType(value, Color)
Return New SolidColorBrush(color)
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
Return Nothing
End Function
End Class
További információért lásd a IValueConverter-t.
Most az egyéni átalakítót használja az alapértelmezett átalakítás helyett, és a diagram így néz ki.
Megismételve, előfordulhat, hogy az alapértelmezett konverziók elérhetők, mivel a típusátalakítók a kötött típusban találhatók. Ez a viselkedés attól függ, hogy mely típuskonverterek érhetők el a célban. Ha kétségei vannak, hozzon létre egy saját konvertert.
Az alábbiakban néhány tipikus forgatókönyvet lásunk, ahol érdemes adatkonvertert implementálni:
Az adatoknak a kultúrától függően másként kell megjelennie. Előfordulhat például, hogy egy pénznemkonvertert vagy egy naptárdátum-/időváltót szeretne implementálni egy adott kultúrában használt konvenciók alapján.
A használt adatok nem feltétlenül egy tulajdonság szöveges értékének módosítására szolgálnak, hanem más érték, például egy kép forrásának vagy a megjelenített szöveg színének vagy stílusának módosítására szolgálnak. A konverterek ebben a példában úgy használhatók, hogy átalakítják egy olyan tulajdonság kötését, amely nem tűnik megfelelőnek, például egy szövegmezőt egy táblázatcella Háttér tulajdonságához kötéssel.
Egynél több vezérlő vagy vezérlőelem több tulajdonsága is ugyanahhoz az adathoz van kötve. Ebben az esetben előfordulhat, hogy az elsődleges kötés csak a szöveget jeleníti meg, míg más kötések konkrét megjelenítési problémákat kezelnek, de továbbra is ugyanazt a kötést használják, mint a forrásinformációk.
A céltulajdonságnak van egy kötések gyűjteménye, amelyet MultiBinding-nak nevezünk. Egy testreszabott IMultiValueConverter használatával hozhat létre végleges értéket a kötésektől származó értékekből a MultiBindingesetében. A szín például piros, kék és zöld értékekből számítható ki, amelyek lehetnek azonos vagy különböző kötési forrásobjektumokból származó értékek. Tekintse meg a MultiBinding példákat és információkat.
Adatkapcsolás gyűjteményekhez
A kötési forrásobjektumok kezelhetők egyetlen objektumként, amelynek tulajdonságai adatokat tartalmaznak, vagy olyan polimorf objektumok adatgyűjtéseként, amelyek gyakran csoportosítva vannak (például egy adatbázisba irányuló lekérdezés eredménye). Eddig csak az egyetlen objektumokhoz való kötésről volt szó. Az adatgyűjtéshez való kötés azonban gyakori forgatókönyv. Például egy gyakori forgatókönyv, hogy ItemsControl-t, mint például ListBox, ListViewvagy TreeView, használnak adatgyűjtés megjelenítésére, amint az a Mi az adatkötés szakaszban látható alkalmazásban történik.
Szerencsére az alapdiagram továbbra is érvényes. Ha ItemsControl köt egy gyűjteményhez, a diagram így néz ki.
Ahogy az ábrán látható, egy ItemsControl gyűjteményobjektumhoz való kötéséhez ItemsControl.ItemsSource tulajdonság a használandó tulajdonság. Úgy gondolhatsz a ItemsSource
-ra, mint a ItemsControltartalmára. A kötés OneWay, mert a ItemsSource
tulajdonság alapértelmezés szerint támogatja OneWay
kötést.
Gyűjtemények implementálása
A IEnumerable felületet megvalósító gyűjtemények számbavétele is megadható. Ha azonban dinamikus kötéseket szeretne beállítani, hogy a gyűjteménybe történő beszúrások vagy törlések automatikusan frissítsák a felhasználói felületet, a gyűjteménynek implementálnia kell a INotifyCollectionChanged felületet. Ez a felület egy eseményt tesz elérhetővé, amelyet a mögöttes gyűjtemény változásakor létre kell tenni.
A WPF biztosítja a ObservableCollection<T> osztályt, amely egy olyan adatgyűjtés beépített implementációja, amely elérhetővé teszi a INotifyCollectionChanged felületet. Ha teljes mértékben támogatni szeretné az adatértékek forrásobjektumokból célokra történő átvitelét, a gyűjtemény minden olyan objektumának, amely támogatja a kötési tulajdonságokat, a INotifyPropertyChanged felületet is implementálnia kell. További információ: Kötésforrások áttekintése.
A saját gyűjtemény implementálása előtt fontolja meg a ObservableCollection<T> vagy a meglévő gyűjteményosztályok egyikét, például List<T>, Collection<T>és BindingList<T>használatát. Ha speciális forgatókönyvvel rendelkezik, és saját gyűjteményt szeretne implementálni, fontolja meg a IListhasználatát, amely nem általános objektumgyűjteményt biztosít, amelyet az index egyenként érhet el, és így a legjobb teljesítményt nyújtja.
Gyűjteménynézetek
Ha a ItemsControl egy adatgyűjtéshez van kötve, érdemes lehet rendezni, szűrni vagy csoportosítani az adatokat. Ehhez gyűjteménynézeteket használ, amelyek a ICollectionView felületet megvalósító osztályok.
Mik azok a gyűjteménynézetek?
A gyűjteménynézet egy olyan réteg a kötési forrásgyűjtemény tetején, amely lehetővé teszi a forrásgyűjtemény rendezésén, szűrésén és csoportosításán alapuló navigálását és megjelenítését anélkül, hogy magát a forrásgyűjteményt kellene módosítania. A gyűjteménynézet a gyűjtemény aktuális elemére mutató mutatót is fenntart. Ha a forrásgyűjtemény implementálja a INotifyCollectionChanged felületet, a CollectionChanged esemény által kiváltott módosítások propagálása a nézetekbe történik.
Mivel a nézetek nem módosítják az alapul szolgáló forrásgyűjteményeket, minden forrásgyűjteményhez több nézet is társítható. Előfordulhat például, hogy Task objektumgyűjteménye van. A nézetek használatával ugyanazokat az adatokat különböző módokon jelenítheti meg. Előfordulhat például, hogy a lap bal oldalán prioritás szerint rendezve szeretné megjeleníteni a tevékenységeket, a jobb oldalon pedig terület szerint csoportosítva.
Nézet létrehozása
A nézet létrehozásának és használatának egyik módja a nézetobjektum közvetlen példányosítása, majd kötési forrásként való használata. Vegyük például a Adatkötési bemutató alkalmazást a Mi az adatkötés szakaszban. Az alkalmazás úgy van megvalósítva, hogy a ListBox egy nézethez kötődik az adatgyűjtés fölött, nem közvetlenül az adatgyűjtéshez. Az alábbi példa a Adatkötési bemutató alkalmazásból származik. A CollectionViewSource osztály egy olyan osztály XAML-proxyja, amely CollectionViewörököl. Ebben a konkrét példában a nézet Source az aktuális alkalmazásobjektum AuctionItems gyűjteményéhez van kötve (ObservableCollection<T>típusú).
<Window.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"
x:Key="listingDataView" />
</Window.Resources>
Az erőforrás ListDataView ezután az alkalmazás elemeinek kötési forrásaként szolgál, például a ListBox.
<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
ItemsSource="{Binding Source={StaticResource listingDataView}}" />
Ha egy másik nézetet szeretne létrehozni ugyanahhoz a gyűjteményhez, létrehozhat egy másik CollectionViewSource példányt, és más x:Key
nevet adhat neki.
Az alábbi táblázat azt mutatja be, hogy a rendszer milyen nézetadattípusokat hoz létre alapértelmezett gyűjteménynézetként, vagy CollectionViewSource a forrásgyűjtemény típusa alapján.
Forrásgyűjtemény típusa | Gyűjteménynézet típusa | Jegyzetek |
---|---|---|
IEnumerable | A CollectionView alapján létrehozott belső típus | Elemek nem csoportosíthatók. |
IList | ListCollectionView | Leggyorsabb. |
IBindingList | BindingListCollectionView |
Alapértelmezett nézet használata
Gyűjteménynézet kötési forrásként való megadása a gyűjteménynézetek létrehozásának és használatának egyik módja. A WPF emellett létrehoz egy alapértelmezett gyűjteménynézetet minden kötésforrásként használt gyűjteményhez. Ha közvetlenül egy gyűjteményhez köt, a WPF az alapértelmezett nézethez köti. Ezt az alapértelmezett nézetet minden kötés megosztja ugyanahhoz a gyűjteményhez, így egy kötött vezérlőelem vagy kód (például rendezés vagy az aktuális elemmutató módosítása, később tárgyalt) által az alapértelmezett nézeten végzett módosítás tükröződik az ugyanazon gyűjteményhez tartozó összes többi kötésben.
Az alapértelmezett nézet lekéréséhez használja a GetDefaultView metódust. Példa: Adatgyűjtés (.NET-keretrendszer) alapértelmezett nézetének lekérése.
Gyűjteménynézetek ADO.NET DataTables használatával
A teljesítmény javítása érdekében az ADO.NET DataTable vagy DataView objektumok gyűjteménynézetei rendezést és szűrést delegálnak a DataView, ami miatt a rendezés és a szűrés meg lesz osztva az adatforrás összes gyűjteménynézetében. Ha engedélyezni szeretné az egyes gyűjteménynézetek egymástól függetlenül történő rendezését és szűrését, inicializálja az egyes gyűjteménynézeteket a saját DataView objektummal.
Rendezés
Ahogy korábban említettük, a nézetek rendezési sorrendet alkalmazhatnak egy gyűjteményre. Mivel az alapul szolgáló gyűjteményben létezik, adatai lehet, hogy tartalmaznak egy releváns, eredendő sorrendet, de az is lehet, hogy nem. A gyűjtemény nézete lehetővé teszi, hogy megrendelést rendeljen, vagy módosítsa az alapértelmezett sorrendet a megadott összehasonlítási feltételek alapján. Mivel ez az adatok ügyfélalapú nézete, gyakori forgatókönyv, hogy a felhasználó a táblázatos adatok oszlopait az oszlopnak megfelelő érték alapján szeretné rendezni. A nézetek használatával ez a felhasználóalapú rendezés ismét alkalmazható anélkül, hogy módosítanák a mögöttes gyűjteményt, vagy újra kellene keresni a gyűjtemény tartalmát. Példa: GridView oszlop rendezése fejlécre kattintáskor (.NET-keretrendszer).
Az alábbi példa az alkalmazás felhasználói felületének "Rendezés kategória és dátum szerint" CheckBox rendezési logikáját mutatja be a Mi az adatkötés szakaszban.
private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e)
{
// Sort the items first by Category and then by StartDate
listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending));
}
Private Sub AddSortCheckBox_Checked(sender As Object, e As RoutedEventArgs)
' Sort the items first by Category And then by StartDate
listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub
Szűrés
A nézetek szűrőt is alkalmazhatnak egy gyűjteményre, így a nézet csak a teljes gyűjtemény egy bizonyos részhalmazát jeleníti meg. Szűrhet egy feltétel szerint az adatokban. Ahogy például az alkalmazás a Mi az adatkötés szakaszban, a "Csak alkuk megjelenítése" CheckBox olyan logikát tartalmaz, amely kiszűri a 25 usd vagy annál több dollárba kerülő elemeket. A következő kódot hajtjuk végre, hogy amikor a CheckBox ki van választva, a ShowOnlyBargainsFilter váljon a Filter eseménykezelővé.
private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (((CheckBox)sender).IsChecked == true)
listingDataView.Filter += ListingDataView_Filter;
else
listingDataView.Filter -= ListingDataView_Filter;
}
Private Sub AddFilteringCheckBox_Checked(sender As Object, e As RoutedEventArgs)
Dim checkBox = DirectCast(sender, CheckBox)
If checkBox.IsChecked = True Then
AddHandler listingDataView.Filter, AddressOf ListingDataView_Filter
Else
RemoveHandler listingDataView.Filter, AddressOf ListingDataView_Filter
End If
End Sub
Az ShowOnlyBargainsFilter eseménykezelő a következő implementációval rendelkezik.
private void ListingDataView_Filter(object sender, FilterEventArgs e)
{
// Start with everything excluded
e.Accepted = false;
// Only inlcude items with a price less than 25
if (e.Item is AuctionItem product && product.CurrentPrice < 25)
e.Accepted = true;
}
Private Sub ListingDataView_Filter(sender As Object, e As FilterEventArgs)
' Start with everything excluded
e.Accepted = False
Dim product As AuctionItem = TryCast(e.Item, AuctionItem)
If product IsNot Nothing Then
' Only include products with prices lower than 25
If product.CurrentPrice < 25 Then e.Accepted = True
End If
End Sub
Ha az egyik CollectionView osztályt használja közvetlenül a CollectionViewSourcehelyett, a Filter tulajdonság használatával visszahívást adhat meg. Példáért lásd: Adatok szűrése nézetben (.NET-keretrendszer).
Csoportosítás
A IEnumerable gyűjteményt megtekintő belső osztály kivételével minden gyűjteménynézet támogatja a csoportosítást, amely lehetővé teszi a felhasználó számára, hogy a gyűjteményt logikai csoportokba partícionálja. A csoportok lehetnek explicitek, ahol a felhasználó megadja a csoportok listáját, vagy implicit módon, ahol a csoportok dinamikusan jönnek létre az adatoktól függően.
Az alábbi példa a "Csoportosítás kategória szerint" CheckBoxlogikáját mutatja be.
// This groups the items in the view by the property "Category"
var groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
listingDataView.GroupDescriptions.Add(groupDescription);
' This groups the items in the view by the property "Category"
Dim groupDescription = New PropertyGroupDescription()
groupDescription.PropertyName = "Category"
listingDataView.GroupDescriptions.Add(groupDescription)
További csoportosítási példa: GridView (.NET-keretrendszer)implementáló ListView-elemek csoportosítása.
Aktuális elemmutatók
A nézetek az aktuális elem fogalmát is támogatják. Gyűjteménynézetben navigálhat az objektumok között. Navigálás közben áthelyez egy elemmutatót, amely lehetővé teszi a gyűjtemény adott helyén található objektum lekérését. Példa: Navigálás a data CollectionView (.NET-keretrendszer)objektumain.
Mivel a WPF csak egy nézet révén tud egy gyűjteményhez kötődni (legyen az egy ön által megadott vagy a gyűjtemény alapértelmezett nézete), minden gyűjteményi kötés rendelkezik egy aktuális elemmutatóval. Nézethez kötéskor a perjel ("/") karakter egy Path
értékben a nézet aktuális elemét jelöli. Az alábbi példában az adatkörnyezet egy gyűjteménynézet. Az első sor a gyűjteményhez kötődik. A második sor a gyűjtemény aktuális eleméhez kapcsolódik. A harmadik sor a gyűjtemény aktuális elemének Description
tulajdonságához kapcsolódik.
<Button Content="{Binding }" />
<Button Content="{Binding Path=/}" />
<Button Content="{Binding Path=/Description}" />
A perjel és a tulajdonságszintaxis halmozható a gyűjtemények hierarchiájának átjárásához is. Az alábbi példa egy Offices
nevű gyűjtemény aktuális eleméhez kapcsolódik, amely a forrásgyűjtemény aktuális elemének tulajdonsága.
<Button Content="{Binding /Offices/}" />
Az aktuális elemmutatót bármilyen, a gyűjteményre alkalmazott rendezés vagy szűrés befolyásolhatja. A rendezés megőrzi az aktuális elemmutatót az utolsó kijelölt elemen, de a gyűjteménynézet most már újrastrukturálva van körülötte. (Lehet, hogy a kijelölt elem korábban a lista elején volt, de most lehet, hogy a kijelölt elem valahol középen van.) A szűrés megőrzi a kijelölt elemet, ha a kijelölés a szűrés után is látható marad. Ellenkező esetben az aktuális elemmutató a szűrt gyűjteménynézet első elemére van állítva.
Master-detail kötési forgatókönyv
Az aktuális elem fogalma nem csak a gyűjtemény elemeinek navigálására, hanem a fő részletkötési forgatókönyvre is hasznos. Vizsgálja meg újra az alkalmazás felhasználói felületét a Mi az adatkötés részben. Az alkalmazásban a ListBox elemen belüli választás határozza meg a ContentControl-ben megjelenő tartalmat. Másképpen fogalmazva, ha egy ListBox elem van kijelölve, a ContentControl a kijelölt elem részleteit jeleníti meg.
A fő részletes forgatókönyvet egyszerűen megvalósíthatja úgy, hogy két vagy több vezérlőt ugyanahhoz a nézethez köt. A következő példa a Adatkötési bemutató résznél, bemutatja az ListBox és a ContentControl jelölését, amelyeket az alkalmazás felhasználói felületén láthat az Mi az adatkötés szakaszban.
<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
ItemsSource="{Binding Source={StaticResource listingDataView}}" />
<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3"
Content="{Binding Source={StaticResource listingDataView}}"
ContentTemplate="{StaticResource detailsProductListingTemplate}"
Margin="9,0,0,0"/>
Figyelje meg, hogy mindkét vezérlő ugyanahhoz a forráshoz van kötve, a listingDataView statikus erőforráshoz (lásd ennek az erőforrásnak a definícióját a 'Hogyan hozzunk létre egy nézetet' szekcióban ). Ez a kötés azért működik, mert amikor egy objektum (ebben az esetben az ContentControl) egy gyűjteménynézethez van kötve, az automatikusan a nézet CurrentItem eleméhez is kapcsolódik. A CollectionViewSource objektumok automatikusan szinkronizálják a pénznemet és a kijelölést. Ha a listavezérlő nem CollectionViewSource objektumhoz van kötve, mint ebben a példában, akkor a IsSynchronizedWithCurrentItem tulajdonságát true
kell beállítania ahhoz, hogy működjön.
További példákért lásd: Gyűjteményhez kötés és információk megjelenítése kiválasztás alapján (.NET-keretrendszer) és A master-detail minta használata hierarchikus adatokkal (.NET-keretrendszer).
Lehet, hogy észrevette, hogy a fenti példa sablont használ. Valójában az adatok nem jelennek meg a kívánt módon sablonok használata nélkül (a ContentControl által explicit módon használt és a ListBoxáltal implicit módon használt adatok). A következő szakaszban áttérünk az adatsablon-készítésre.
Adatátszerkesztés
Adatsablonok használata nélkül az alkalmazás felhasználói felülete a Példa adatkötésre szakaszban a következőhöz hasonlóan nézne ki:
adatkötési bemutató
Az előző szakaszban látható példában látható, hogy a ListBox vezérlőelem és a ContentControl is az AuctionItemösszes gyűjteményobjektumához (pontosabban a gyűjteményobjektum feletti nézethez) van kötve. Az adatgyűjtés megjelenítésére vonatkozó konkrét utasítások nélkül a ListBox megjeleníti az egyes objektumok sztring-ábrázolását az alapul szolgáló gyűjteményben, a ContentControl pedig annak az objektumnak a sztringképét, amelyhez hozzá van kötve.
A probléma megoldásához az alkalmazás meghatározza DataTemplates. Az előző szakaszban látható példában látható módon a ContentControl explicit módon használja a detailsProductListingTemplate adatsablont. A ListBox vezérlőelem implicit módon az alábbi adatsablont használja a gyűjtemény AuctionItem objektumainak megjelenítésekor.
<DataTemplate DataType="{x:Type src:AuctionItem}">
<Border BorderThickness="1" BorderBrush="Gray"
Padding="7" Name="border" Margin="3" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="86"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
Fill="Yellow" Stroke="Black" StrokeThickness="1"
StrokeLineJoin="Round" Width="20" Height="20"
Stretch="Fill"
Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
Visibility="Hidden" Name="star"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
Name="descriptionTitle"
Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
<TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2"
Text="{Binding Path=Description}"
Style="{StaticResource textStyleTextBlock}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
Name="currentPriceTitle"
Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
<StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
<TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
<TextBlock Name="CurrentPriceDTDataType"
Text="{Binding Path=CurrentPrice}"
Style="{StaticResource textStyleTextBlock}"/>
</StackPanel>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=SpecialFeatures}">
<DataTrigger.Value>
<src:SpecialFeatures>Color</src:SpecialFeatures>
</DataTrigger.Value>
<DataTrigger.Setters>
<Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
<Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
<Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
<Setter Property="BorderThickness" Value="3" TargetName="border" />
<Setter Property="Padding" Value="5" TargetName="border" />
</DataTrigger.Setters>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SpecialFeatures}">
<DataTrigger.Value>
<src:SpecialFeatures>Highlight</src:SpecialFeatures>
</DataTrigger.Value>
<Setter Property="BorderBrush" Value="Orange" TargetName="border" />
<Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
<Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
<Setter Property="Visibility" Value="Visible" TargetName="star" />
<Setter Property="BorderThickness" Value="3" TargetName="border" />
<Setter Property="Padding" Value="5" TargetName="border" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
A két adat sablon használatával az eredményül kapott felhasználói felület jelenik meg a „Mi az adatkötés” című, és címkével ellátott szakaszban. Ahogy a képernyőképen látható, amellett, hogy lehetővé teszi az adatok vezérlőkbe való elhelyezését, a DataTemplates lehetővé teszi, hogy lenyűgöző vizualizációkat definiáljon az adatokhoz. A fenti DataTemplate példában a DataTriggers például úgy vannak használva, hogy a AuctionItemok, amelyek SpecialFeatures értékei a HighLight, narancssárga szegéllyel és csillaggal jelenjenek meg.
Az adatsablonokkal kapcsolatos további információkért tekintse meg a(z) Adatsablonok áttekintése (.NET-keretrendszer).
Adatérvényesítés
A felhasználói bemenetet használó legtöbb alkalmazásnak érvényesítési logikával kell rendelkeznie annak érdekében, hogy a felhasználó megadta a várt adatokat. Az ellenőrzési ellenőrzések típuson, tartományon, formátumon vagy más alkalmazásspecifikus követelményeken alapulhatnak. Ez a szakasz az adatérvényesítés működését ismerteti a WPF-ben.
Érvényesítési szabályok társítása kötéssel
A WPF adatkötési modell lehetővé teszi, hogy ValidationRules társítsa a Binding objektumhoz. Az alábbi példa például egy TextBox egy StartPrice
nevű tulajdonsághoz köti, és hozzáad egy ExceptionValidationRule objektumot a Binding.ValidationRules tulajdonsághoz.
<TextBox Name="StartPriceEntryForm" Grid.Row="2"
Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
<TextBox.Text>
<Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Egy ValidationRule objektum ellenőrzi, hogy egy tulajdonság értéke érvényes-e. A WPF kétféle beépített ValidationRule objektummal rendelkezik:
A ExceptionValidationRule ellenőrzi a kötési forrástulajdonság frissítése során fellépő kivételeket. Az előző példában
StartPrice
egész típusú. Amikor a felhasználó olyan értéket ad meg, amely nem konvertálható egész számmá, kivétel lép fel, ami miatt a kötés érvénytelenként lesz megjelölve. A ExceptionValidationRule explicit megadásának másik szintaxisa, ha a ValidatesOnExceptions tulajdonságottrue
-re állítja a Binding vagy MultiBinding objektumon.Egy DataErrorValidationRule objektum ellenőrzi a IDataErrorInfo felületet implementáló objektumok által kiváltott hibákat. Az érvényesítési szabály használatával kapcsolatos további információkért lásd: DataErrorValidationRule. A DataErrorValidationRule explicit beállításának alternatív szintaxisa, hogy a ValidatesOnDataErrors tulajdonságot
true
értékre állítja a Binding vagy MultiBinding objektumán.
A ValidationRule osztályból származó és a Validate metódus implementálásával saját érvényesítési szabályt is létrehozhat. Az alábbi példa a Terméklista hozzáadása "Kezdő dátum" TextBox által használt szabályt mutatja be a Mi az adatkötés szakaszból.
public class FutureDateRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
// Test if date is valid
if (DateTime.TryParse(value.ToString(), out DateTime date))
{
// Date is not in the future, fail
if (DateTime.Now > date)
return new ValidationResult(false, "Please enter a date in the future.");
}
else
{
// Date is not a valid date, fail
return new ValidationResult(false, "Value is not a valid date.");
}
// Date is valid and in the future, pass
return ValidationResult.ValidResult;
}
}
Public Class FutureDateRule
Inherits ValidationRule
Public Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As ValidationResult
Dim inputDate As Date
' Test if date is valid
If Date.TryParse(value.ToString, inputDate) Then
' Date is not in the future, fail
If Date.Now > inputDate Then
Return New ValidationResult(False, "Please enter a date in the future.")
End If
Else
' // Date Is Not a valid date, fail
Return New ValidationResult(False, "Value is not a valid date.")
End If
' Date is valid and in the future, pass
Return ValidationResult.ValidResult
End Function
End Class
A StartDateEntryFormTextBox ezt a FutureDateRulehasználja, ahogyan az alábbi példában is látható.
<TextBox Name="StartDateEntryForm" Grid.Row="3"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
<TextBox.Text>
<Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged"
Converter="{StaticResource dateConverter}" >
<Binding.ValidationRules>
<src:FutureDateRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Mivel a UpdateSourceTrigger érték PropertyChanged, a kötésmotor minden billentyűleütésnél frissíti a forrásértéket, ami azt jelenti, hogy minden billentyűleütésen ellenőrzi a ValidationRules gyűjtemény minden szabályát. Erről bővebben az Érvényesítési folyamat szakaszban olvashat.
Vizuális visszajelzés küldése
Ha a felhasználó érvénytelen értéket ad meg, érdemes lehet visszajelzést küldeni az alkalmazás felhasználói felületén megjelenő hibáról. Az ilyen visszajelzések egyik módja, ha a Validation.ErrorTemplate csatolt tulajdonságot egyéni ControlTemplate-re állítja be. Ahogyan az előző alszakaszban látható, a StartDateEntryFormTextBox egy ErrorTemplate-t használ, amit validationTemplate-nek hívnak. Az alábbi példa a validationTemplatedefinícióját mutatja be.
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
A AdornedElementPlaceholder elem határozza meg, hogy hová kell helyezni a díszítendő vezérlőt.
Emellett ToolTip is használhatja a hibaüzenet megjelenítéséhez. A StartDateEntryForm és a StartPriceEntryFormTextBoxis a textStyleTextBoxstílust használja, amely létrehoz egy ToolTip, amelyik megjeleníti a hibaüzenetet. Az alábbi példa textStyleTextBoxdefinícióját mutatja be. A csatolt tulajdonság Validation.HasError akkor true
, ha a kötött elem tulajdonságaihoz tartozó kötések közül egy vagy több hibás.
<Style x:Key="textStyleTextBox" TargetType="TextBox">
<Setter Property="Foreground" Value="#333333" />
<Setter Property="MaxLength" Value="40" />
<Setter Property="Width" Value="392" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding (Validation.Errors).CurrentItem.ErrorContent, RelativeSource={RelativeSource Self}}" />
</Trigger>
</Style.Triggers>
</Style>
Az egyéni ErrorTemplate és a ToolTipesetén a StartDateEntryFormTextBox az alábbihoz hasonlóan néz ki érvényesítési hiba esetén.
Ha a Binding rendelkezik érvényesítési szabályokkal, de nem ad meg ErrorTemplate-t a kötött vezérlőelemen, a rendszer alapértelmezett ErrorTemplate-t fog használni, hogy értesítse a felhasználókat, ha érvényesítési hiba merül fel. Az alapértelmezett ErrorTemplate egy vezérlősablon, amely piros szegélyt határoz meg az adorner rétegben. Az alapértelmezett ErrorTemplate és a ToolTipesetén a StartPriceEntryFormTextBox felhasználói felülete érvényesítési hiba esetén az alábbihoz hasonló.
A párbeszédpanelek összes vezérlőjének ellenőrzésére szolgáló logikát bemutató példát a párbeszédpanelek áttekintésiegyéni párbeszédpanelek szakaszában talál.
Érvényesítési folyamat
Az ellenőrzés általában akkor történik, ha a cél értéke átkerül a kötés forrástulajdonságába. Ez az átvitel TwoWay és OneWayToSource kötéseken történik. Ismételten: A forrásfrissítés oka a UpdateSourceTrigger tulajdonság értékétől függ, ahogyan azt a szakaszban, a Mi aktiválja a forrásfrissítéseket részben le van írva.
Az alábbi elemek az érvényesítési folyamatát ismertetik. Ha a folyamat során bármikor érvényesítési hiba vagy más típusú hiba lép fel, a folyamat leáll:
A kötési motor ellenőrzi, hogy az adott Bindingesetében vannak-e olyan egyéni ValidationRule objektumok, amelyeknél a ValidationStepRawProposedValue van beállítva, ebben az esetben meghívja az egyes ValidationRule-ökön a Validate metódust, amíg egyikük hibába nem ütközik, vagy mindaddig, amíg az összes át nem megy.
A kötőmotor ezután meghívja a konvertert, ha létezik ilyen.
Ha a konverter sikeres, a kötési motor ellenőrzi, hogy vannak-e olyan egyéni ValidationRule objektumok, amelyeknek ValidationStep az adott BindingConvertedProposedValue van beállítva. Ebben az esetben meghívja a Validate metódust minden olyan ValidationRule esetében, amelynek ValidationStep beállítása ConvertedProposedValue, egészen addig, amíg az egyik hibába nem ütközik, vagy amíg mindegyik sikeresen végrehajtódik.
A kötési motor beállítja a forrástulajdonságot.
A kötési motor ellenőrzi, hogy vannak-e olyan egyéni ValidationRule objektumok, amelyeknél az adott BindingValidationStep értéke UpdatedValue, ebben az esetben minden olyan ValidationRule-ön meghívja a Validate metódust, amelynél ValidationStepUpdatedValue-re van beállítva, egészen addig, amíg egyikük hibát nem jelez, vagy mindegyik sikeresen lefut. Ha egy DataErrorValidationRule egy kötéshez van társítva, és a ValidationStep az alapértelmezett értékre van állítva, UpdatedValue, a DataErrorValidationRule ekkor be van jelölve. Ezen a ponton minden olyan kötés ellenőrizve van, amelynél ValidatesOnDataErrors
true
-re van beállítva.A kötési motor ellenőrzi, hogy vannak-e olyan egyéni ValidationRule objektumok, amelyeknél a ValidationStep értéke CommittedValue az adott Bindingesetében. Ebben az esetben meghívja a Validate metódust minden olyan ValidationRule esetén, amelynek ValidationStep értéke CommittedValue, addig, amíg valamelyik hibát nem jelez, vagy mind sikeresen le nem fut.
Ha egy ValidationRule nem halad át a folyamat során, a kötési motor létrehoz egy ValidationError objektumot, és hozzáadja a kötött elem Validation.Errors gyűjteményéhez. Mielőtt a kötésmotor bármely adott lépésnél futtatná a ValidationRule objektumokat, eltávolítja a ValidationError elemeket, amelyeket a lépés során adtak hozzá a kötött elem Validation.Errors csatolt tulajdonságához. Ha például meghibásodik egy ValidationRule, amelynek ValidationStep értéke UpdatedValue, akkor az érvényesítési folyamat következő alkalmával a kötési motor azonnal eltávolítja a ValidationError-at, mielőtt bármely ValidationRule-et meghívna, amelynek ValidationStepUpdatedValue-ra van állítva.
Ha Validation.Errors nem üres, az elem Validation.HasError csatolt tulajdonsága true
. Ha a BindingNotifyOnValidationError tulajdonsága true
értékre van állítva, akkor a kötőmotor kiváltja a Validation.Error csatolt eseményt az elemen.
Azt is vegye figyelembe, hogy az érvényes értékátvitel bármely irányban (célból forrásba vagy forrásból célba) törli a Validation.Errors csatolt tulajdonságot.
Ha a kötéshez ExceptionValidationRule van társítva, vagy ha a ValidatesOnExceptions tulajdonság true
van beállítva, és a kötési motor a forrás beállításakor kivételt jelez, a kötési motor ellenőrzi, hogy van-e UpdateSourceExceptionFilter. A UpdateSourceExceptionFilter visszahívással egyéni kezelőt biztosíthat a kivételek kezeléséhez. Ha nincs megadva UpdateSourceExceptionFilter a Binding-on, a kötési motor létrehoz egy ValidationError-t a kivétellel, és hozzáadja azt a kötött elem Validation.Errors gyűjteményéhez.
Hibakeresési mechanizmus
Beállíthatja a csatolt tulajdonság PresentationTraceSources.TraceLevel egy kötéssel kapcsolatos objektumon, hogy információt kapjon egy adott kötés állapotáról.
Lásd még:
.NET Desktop feedback