Megosztás a következőn keresztül:


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.

diagram, amely az alapszintű adatkötési modellt mutatja be.

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 a Employee.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 DependencyObjectszá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:

Adatkötési adatfolyam

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

Az UpdateSourceTrigger tulajdonság szerepkörét bemutató diagram.

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.

Adatkötési minta képernyőképe

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.

Terméklista oldal hozzáadása

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.

Diagram, amely az adatkötés háttértulajdonságát mutatja.

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 ColorNamenevű sztringtulajdonságot tartalmaz. Ez a példa a myTextszö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:

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.

Diagram, amely az adatkötés Alapértelmezett tulajdonságát mutatja.

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.

egyéni adatkötési konvertert bemutató diagram.

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.

Az adatkötési ItemsControl objektumot bemutató diagram.

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 Officesnevű 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ó adatsablonok nélkül

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

Dátumhoz kapcsolódó adatkötés érvényesítési hiba

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

Az ár adatkötés érvényesítési hibája

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:

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

  2. A kötőmotor ezután meghívja a konvertert, ha létezik ilyen.

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

  4. A kötési motor beállítja a forrástulajdonságot.

  5. 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 ValidatesOnDataErrorstrue-re van beállítva.

  6. 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: