Wie verwende ich RelativeSource
WPF-Bindungen und welche Anwendungsfälle gibt es?
.net
wpf
xaml
data-binding
relativesource
David Schmitt
quelle
quelle
AncestorType
.FindAncestor
vorher weglasse ,AncestorType
wird folgende Fehlermeldung angezeigt: "RelativeSource befindet sich nicht im FindAncestor-Modus". (In VS2013, Community-Version){Binding Path=DataContext.SomeProperty, RelativeSource=...
. Dies war für mich als Neuling etwas unerwartet, als ich versuchte, innerhalb einer DataTemplate an den DataContext eines Elternteils zu binden.Das Standardattribut von
RelativeSource
ist dieMode
Eigenschaft. Ein vollständiger Satz gültiger Werte wird hier angegeben ( von MSDN ):PreviousData Ermöglicht das Binden des vorherigen Datenelements (nicht des Steuerelements, das das Datenelement enthält) in die Liste der angezeigten Datenelemente.
TemplatedParent Bezieht sich auf das Element, auf das die Vorlage (in der das datengebundene Element vorhanden ist) angewendet wird. Dies ähnelt dem Festlegen einer TemplateBindingExtension und gilt nur, wenn sich die Bindung in einer Vorlage befindet.
Selbst Bezieht sich auf das Element, für das Sie die Bindung festlegen, und ermöglicht es Ihnen, eine Eigenschaft dieses Elements an eine andere Eigenschaft desselben Elements zu binden.
FindAncestor Bezieht sich auf den Vorfahren in der übergeordneten Kette des datengebundenen Elements. Sie können dies verwenden, um an einen Vorfahren eines bestimmten Typs oder dessen Unterklassen zu binden. Dies ist der Modus, den Sie verwenden, wenn Sie AncestorType und / oder AncestorLevel angeben möchten.
quelle
Hier ist eine visuellere Erklärung im Kontext einer MVVM-Architektur:
quelle
{Binding Message}
(etwas einfacher ...)Path=DataContext.Message
, dass die Bindung funktioniert. Dies ist sinnvoll, da Sie relative Bindungen zu Breite / Höhe / etc. einer Kontrolle.Bechir Bejaoui stellt in seinem Artikel hier die Anwendungsfälle der RelativeSources in WPF vor :
quelle
ListView
. Der Elternteil hat 2 weitereListView
Ebenen darunter. Das half mir verhindern Gabe von Daten in jedem nachfolgenden vm jedesListView
‚sDataTemplate
In der WPF-
RelativeSource
Bindung werden dreiproperties
zu setzen:1. Modus: Dies ist ein Modus
enum
, der vier Werte haben kann:2. AncestorType: Wenn der Modus aktiviert ist,
FindAncestor
definieren Sie, welcher Ahnen-Typ3. AncestorLevel: Wenn der Modus
FindAncestor
dann die Ebene des Vorfahren ist (wenn zwei gleiche Elterntypen vorhanden sindvisual tree
)Hier ist ein Referenzlink .
quelle
Vergessen Sie nicht TemplatedParent:
oder
quelle
Es ist erwähnenswert, dass für diejenigen, die über dieses Denken von Silverlight stolpern:
Silverlight bietet nur eine reduzierte Teilmenge dieser Befehle
quelle
Ich habe eine Bibliothek erstellt, um die Bindungssyntax von WPF zu vereinfachen und die Verwendung von RelativeSource zu vereinfachen. Hier sind einige Beispiele. Vor:
Nach:
Hier ist ein Beispiel dafür, wie die Methodenbindung vereinfacht wird. Vor:
Nach:
Sie finden die Bibliothek hier: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
Beachten Sie im Beispiel 'BEFORE', das ich für die Methodenbindung verwende, dass der Code bereits optimiert wurde, indem
RelayCommand
der zuletzt überprüfte Code kein nativer Teil von WPF ist. Ohne das wäre das Beispiel "VORHER" noch länger gewesen.quelle
Einige nützliche Kleinigkeiten:
So geht's meistens im Code:
Ich habe dies größtenteils aus Binding Relative Source im Code Behind kopiert .
Außerdem ist die MSDN-Seite in Bezug auf Beispiele ziemlich gut: RelativeSource-Klasse
quelle
Ich habe gerade gepostet andere Lösung für den Zugriff auf den DataContext eines übergeordneten Elements in Silverlight veröffentlicht, die für mich funktioniert. Es verwendet
Binding ElementName
.quelle
Ich habe nicht jede Antwort gelesen, aber ich möchte diese Informationen nur im Falle einer relativen Quellbefehlsbindung einer Schaltfläche hinzufügen.
Wenn Sie eine relative Quelle mit verwenden
Mode=FindAncestor
, muss die Bindung wie folgt aussehen:Wenn Sie Ihrem Pfad keinen DataContext hinzufügen, kann die Eigenschaft zur Ausführungszeit nicht abgerufen werden.
quelle
Dies ist ein Beispiel für die Verwendung dieses Musters, das bei leeren Datagrids für mich funktioniert hat.
quelle
Wenn ein Element nicht Teil des visuellen Baums ist, funktioniert RelativeSource niemals.
In diesem Fall müssen Sie eine andere Technik ausprobieren, die von Thomas Levesque entwickelt wurde.
Er hat die Lösung in seinem Blog unter [WPF] Wie man an Daten bindet, wenn der DataContext nicht vererbt wird . Und es funktioniert absolut hervorragend!
Für den unwahrscheinlichen Fall, dass sein Blog nicht verfügbar ist, enthält Anhang A eine Spiegelkopie seines Artikels .
Bitte hier nicht kommentieren, bitte direkt in seinem Blogbeitrag kommentieren .
Anhang A: Spiegel des Blogposts
Die DataContext-Eigenschaft in WPF ist äußerst praktisch, da sie automatisch von allen untergeordneten Elementen des Elements geerbt wird, dem Sie sie zuweisen. Daher müssen Sie es nicht für jedes Element, das Sie binden möchten, erneut festlegen. In einigen Fällen ist der DataContext jedoch nicht verfügbar: Dies geschieht für Elemente, die nicht Teil des visuellen oder logischen Baums sind. Es kann dann sehr schwierig sein, eine Eigenschaft an diese Elemente zu binden…
Lassen Sie uns anhand eines einfachen Beispiels veranschaulichen: Wir möchten eine Liste der Produkte in einem DataGrid anzeigen. Im Raster möchten wir in der Lage sein, die Spalte Preis basierend auf dem Wert einer ShowPrice-Eigenschaft, die vom ViewModel verfügbar gemacht wird, ein- oder auszublenden. Der naheliegende Ansatz besteht darin, die Sichtbarkeit der Spalte an die ShowPrice-Eigenschaft zu binden:
Leider hat das Ändern des Werts von ShowPrice keine Auswirkung, und die Spalte ist immer sichtbar. Warum? Wenn wir uns das Ausgabefenster in Visual Studio ansehen, sehen wir die folgende Zeile:
Wir können versuchen, die Bindung zu optimieren, um das gewünschte Ergebnis zu erzielen, indem wir beispielsweise die RelativeSource auf das DataGrid selbst setzen:
Oder wir können ein an ShowPrice gebundenes Kontrollkästchen hinzufügen und versuchen, die Spaltensichtbarkeit an die IsChecked-Eigenschaft zu binden, indem wir den Elementnamen angeben:
Aber keine dieser Problemumgehungen scheint zu funktionieren. Wir erzielen immer das gleiche Ergebnis.
An diesem Punkt scheint es der einzig praktikable Ansatz zu sein, die Spaltensichtbarkeit in Code-Behind zu ändern, was wir normalerweise lieber vermeiden, wenn wir das MVVM-Muster verwenden… Aber ich werde nicht so schnell aufgeben, zumindest nicht während es andere Optionen gibt, die berücksichtigt werden müssen 😉
Die Lösung für unser Problem ist eigentlich recht einfach und nutzt die Freezable-Klasse. Der Hauptzweck dieser Klasse besteht darin, Objekte zu definieren, die einen veränderbaren und schreibgeschützten Status haben. Das Interessante in unserem Fall ist jedoch, dass Freezable-Objekte den DataContext erben können, auch wenn sie sich nicht im visuellen oder logischen Baum befinden. Ich kenne den genauen Mechanismus nicht, der dieses Verhalten ermöglicht, aber wir werden ihn nutzen, damit unsere Bindung funktioniert…
Die Idee ist, eine Klasse zu erstellen (ich habe sie aus Gründen, die sehr bald offensichtlich werden sollten, BindingProxy genannt), die Freezable erbt und eine Datenabhängigkeitseigenschaft deklariert:
Wir können dann eine Instanz dieser Klasse in den Ressourcen des DataGrid deklarieren und die Data-Eigenschaft an den aktuellen DataContext binden:
Der letzte Schritt besteht darin, dieses BindingProxy-Objekt (mit StaticResource leicht zugänglich) als Quelle für die Bindung anzugeben:
Beachten Sie, dass dem Bindungspfad "Daten" vorangestellt wurde, da der Pfad jetzt relativ zum BindingProxy-Objekt ist.
Die Bindung funktioniert jetzt ordnungsgemäß und die Spalte wird basierend auf der ShowPrice-Eigenschaft ordnungsgemäß angezeigt oder ausgeblendet.
quelle