Frage

Wie verwende ich RelativeSource mit WPF-Bindungen und was sind die verschiedenen Anwendungsfälle?

War es hilfreich?

Lösung

Wenn Sie auf das Objekt auf eine andere Eigenschaft binden:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}

Wenn Sie eine Eigenschaft auf einem Vorfahren zu bekommen:

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}

Wenn Sie eine Immobilie auf den Templat-Eltern zu bekommen (so Sie 2-Wege-Bindungen in einem Control tun können)

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

oder kürzer (dies funktioniert nur für OneWay Bindungen):

{TemplateBinding Path=PathToProperty}

Andere Tipps

Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

Das Standardattribut von RelativeSource ist der Mode Eigentum.Ein vollständiger Satz gültiger Werte ist hier angegeben (von MSDN):

  • VorherigeDaten Ermöglicht Ihnen, das vorherige Datenelement (nicht das Steuerelement, das das Datenelement enthält) in der Liste der angezeigten Datenelemente zu binden.

  • 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 ist nur anwendbar, wenn sich die Bindung innerhalb einer Vorlage befindet.

  • Selbst Bezieht sich auf das Element, für das Sie die Bindung festlegen, und ermöglicht 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 eine Bindung an einen Vorfahren eines bestimmten Typs oder seiner Unterklassen herzustellen.Dies ist der Modus, den Sie verwenden, wenn Sie AncestorType und/oder AncestorLevel angeben möchten.

Hier ist eine visuelle Erklärung im Rahmen einer MVVM Architektur:

eingeben Bild Beschreibung hier

Stellen Sie sich vor, diesen Fall, ein Rechteck, das wir wollen, dass seine Höhe zu seiner Breite immer gleich ist, lassen Sie ein Quadrat sagen. Wir können dies mit dem Elementnamen mit

<Rectangle Fill="Red" Name="rectangle" 
                    Height="100" Stroke="Black" 
                    Canvas.Top="100" Canvas.Left="100"
                    Width="{Binding ElementName=rectangle,
                    Path=Height}"/>

Aber in diesem obigen Fall sind wir verpflichtet, den Namen des Bindungsobjekts anzuzeigen, nämlich das Rechteck. Wir können den gleichen Zweck erreichen anders die Relative mit

<Rectangle Fill="Red" Height="100" 
                   Stroke="Black" 
                   Width="{Binding RelativeSource={RelativeSource Self},
                   Path=Height}"/>

Für diesen Fall sind wir nicht verpflichtet, den Namen des Bindungsobjekts zu erwähnen und die Breite wird immer gleich die Höhe, wenn die Höhe geändert wird.

Wenn Sie die Breite zu sein, die Hälfte der Höhe auf Parameter, dann können Sie dies tun, indem einem Konverter an die Binding-Markup-Erweiterung hinzufügen. Lassen Sie uns einen anderen Fall vorstellen, jetzt:

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
                   Path=Parent.ActualWidth}"/>

Der obige Fall ist eine bestimmte Eigenschaft eines bestimmten Elements zu einer seiner direkten Mutter diejenigen zu binden verwendet, wie dieses Element eine Eigenschaft enthält, die Eltern genannt wird. Dies führt uns zu einem anderen relativen Quelle-Modus, der der FindAncestor ist.

Bechir Bejaoui macht die Anwendungsfälle der RelativeSources in WPF in seinem Artikel hier :

  

Die Relative ist eine Markup-Erweiterung, die insbesondere verwendet wird,   Bindung Fällen, wenn wir versuchen, eine Eigenschaft eines bestimmten Objekts zu binden   eine andere Eigenschaft des Objekts selbst, wenn wir versuchen, eine Eigenschaft zu binden   ein Objekt auf einen anderen seinen relativ Eltern, wenn Bindung a   Abhängigkeitseigenschaft Wert auf ein Stück XAML bei Custom Controls   Entwicklung und schließlich bei einem Differential einer Serie unter Verwendung von   ein gebundenen Daten. All diese Situationen sind als relative Quelle ausgedrückt   Modi. Ich werde all diese Fälle einer nach dem anderen aus.

     
      
  1. Modus Selbst:
  2.   
     

Stellen Sie sich vor, diesen Fall, ein Rechteck, das wir, dass seine Höhe wollen, ist immer   gleich seiner Breite, lassen Sie uns ein Quadrat sagen. Wir können dies tun, die mit   Elementname

<Rectangle Fill="Red" Name="rectangle" 
                Height="100" Stroke="Black" 
                Canvas.Top="100" Canvas.Left="100"
                Width="{Binding ElementName=rectangle,
                Path=Height}"/>
     

Aber in diesem obigen Fall sind wir verpflichtet, den Namen der anzuzeigen   Bindungsobjekt, nämlich das Rechteck. Wir können den gleichen Zweck erreichen   anders mit der Relative

<Rectangle Fill="Red" Height="100" 
               Stroke="Black" 
               Width="{Binding RelativeSource={RelativeSource Self},
               Path=Height}"/>
     

Für diesen Fall sind wir nicht verpflichtet, den Namen der Bindung zu erwähnen   Objekt und die Breite wird auf die Höhe immer gleich sein, wenn die   Höhe wird geändert.

     

Wenn Sie die Breite auf Parameter die Hälfte der Höhe zu sein, dann   Sie können dies durch einen Konverter an die Binding-Markup-Erweiterung hinzufügen.   Lassen Sie uns einen anderen Fall vorstellen, jetzt:

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
               Path=Parent.ActualWidth}"/>
     

Der obige Fall ist eine bestimmte Eigenschaft eines bestimmten Elements zu binden verwendet   einer seiner direkten Mutter one als dieses Element hält eine Eigenschaft, die ist   genannt Parent. Dies führt uns zu einem anderen relativen Quelle-Modus, ist   der FindAncestor ein.

     
      
  1. Modus FindAncestor
  2.   
     

In diesem Fall ist eine Eigenschaft eines bestimmten Elements wird zu einem seiner gebunden werden   Eltern, Corse. Der wesentliche Unterschied zu dem obigen Fall ist die Tatsache,   das, es ist an Ihnen, den Vorfahren Typ und den Vorfahren zu bestimmen   Rang in der Hierarchie die Eigenschaft zu binden. Durch die Art und Weise versuchen, mit zu spielen   dieses Stück XAML

<Canvas Name="Parent0">
    <Border Name="Parent1"
             Width="{Binding RelativeSource={RelativeSource Self},
             Path=Parent.ActualWidth}"
             Height="{Binding RelativeSource={RelativeSource Self},
             Path=Parent.ActualHeight}">
        <Canvas Name="Parent2">
            <Border Name="Parent3"
            Width="{Binding RelativeSource={RelativeSource Self},
           Path=Parent.ActualWidth}"
           Height="{Binding RelativeSource={RelativeSource Self},
              Path=Parent.ActualHeight}">
               <Canvas Name="Parent4">
               <TextBlock FontSize="16" 
               Margin="5" Text="Display the name of the ancestor"/>
               <TextBlock FontSize="16" 
                 Margin="50" 
            Text="{Binding RelativeSource={RelativeSource  
                       FindAncestor,
                       AncestorType={x:Type Border}, 
                       AncestorLevel=2},Path=Name}" 
                       Width="200"/>
                </Canvas>
            </Border>
        </Canvas>
     </Border>
   </Canvas>
     

Die oben beschriebene Situation ist von zwei TextBlock- Elemente diejenigen eingebettet sind   innerhalb einer Reihe von Grenzen und Segeltuchelementen repräsentieren diejenigen ihre   hierarchisch Eltern. Der zweite Textblock wird angezeigt, den Namen   der gegebene Elternteil in der relativen Quellebene.

     

versuchen So AncestorLevel = 2 bis AncestorLevel = 1 und sehen Sie zu ändern, was   das passiert. Dann versuchen, die Art des Vorfahren zu ändern aus   AncestorType = Border zu AncestorType = Leinwand und sehen, was passiert.

     

Der angezeigte Text wird entsprechend den Vorfahren Typen verändern und   Niveau. Was ist dann geschehen, wenn die Vorfahre Ebene nicht geeignet das ist   Vorfahrtyp? Das ist eine gute Frage, ich weiß, dass Sie über zu   Frag es. Die Antwort ist, werden keine Ausnahmen geworfen und Nichtigkeiten werden wird   wird auf der TextBlock- Ebene angezeigt.

     
      
  1. TemplatedParent
  2.   
     

Dieser Modus ermöglicht eine gegebene Eigenschaft Control auf eine Eigenschaft binden   die Steuerung, die die Control angewandt wird. Um gut   versteht das Problem hier ist ein Beispiel unten

<Window.Resources>
<ControlTemplate x:Key="template">
        <Canvas>
            <Canvas.RenderTransform>
                <RotateTransform Angle="20"/>
                </Canvas.RenderTransform>
            <Ellipse Height="100" Width="150" 
                 Fill="{Binding 
            RelativeSource={RelativeSource TemplatedParent},
            Path=Background}">

              </Ellipse>
            <ContentPresenter Margin="35" 
                  Content="{Binding RelativeSource={RelativeSource  
                  TemplatedParent},Path=Content}"/>
        </Canvas>
    </ControlTemplate>
</Window.Resources>
    <Canvas Name="Parent0">
    <Button   Margin="50" 
              Template="{StaticResource template}" Height="0" 
              Canvas.Left="0" Canvas.Top="0" Width="0">
        <TextBlock FontSize="22">Click me</TextBlock>
    </Button>
 </Canvas>
     

Wenn ich die Eigenschaften eines bestimmten Kontrolle ihrer Kontrolle anwenden möchten   Vorlage dann kann ich den TemplatedParent-Modus verwenden. Da ist auch ein   ähnlich einer zu dieser Auszeichnungs Erweiterung, die das Template ist   Das ist eine Art kurzer Hand des ersten, aber die   Template wird bei der Kompilierung im Gegensatz der evaluierten   TemplatedParent die Gerade nach der ersten Laufzeit ausgewertet. Wie   Sie können in der unten Figur, den Hintergrund und den Inhalt bemerke   werden innerhalb der Taste an die Steuer Vorlage angewendet.

In WPF RelativeSource Bindung macht drei properties zu setzen:

1. Modus: Dies ist ein enum, die vier Werte haben könnte:

  

ein. PreviousData (value=0): Es weist den vorherigen Wert des property zu   das gebundene ein

     

b. TemplatedParent (value=1): Dies wird verwendet, wenn die Definition der templates von   jede Kontrolle und möchte auf einen Wert / Vermögen des control binden.

     

Beispiel: definieren ControlTemplate:

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>
  

c. Selbst (value=2.): Wenn wir von einem self oder property Selbst binden möchten

     

Beispiel: Senden Zustand checkbox als CommandParameter geprüft, während die Command auf CheckBox Einstellung

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />
  

d. FindAncestor (value=3): Wenn wollen von einem Elternteil control binden   in Visual Tree.

     

Beispiel: Binden eines checkbox in records wenn ein grid, wenn header checkbox wird geprüft

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />

2. AncestorType: , wenn Modus FindAncestor dann definieren, welche Art von Vorfahren

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}

3. AncestorLevel: , wenn Modus FindAncestor dann auf welcher Ebene der Vorfahren (wenn es zwei gleiche Art von Eltern in visual tree)

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}
  

Über alle Anwendungsfälle für RelativeSource binding .

Hier ist ein Referenz-Link .

Vergessen Sie nicht TemplatedParent:

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>

oder

{Binding RelativeSource={RelativeSource TemplatedParent}}

Es ist bemerkenswert, dass diejenigen, für die über dieses Denken von Silverlight zu stolpern:

Silverlight bietet eine reduzierte Teilmenge nur, diese Befehle

habe ich eine Bibliothek, die die Bindungssyntax von WPF zu vereinfachen, einschließlich macht es einfacher Relative zu verwenden. Hier sind einige Beispiele. Vorher:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
{Binding Path=Text, ElementName=MyTextBox}

Nach:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}

Hier ist ein Beispiel dafür, wie Methodenbindung vereinfacht. Vorher:

// C# code
private ICommand _saveCommand;
public ICommand SaveCommand {
 get {
  if (_saveCommand == null) {
   _saveCommand = new RelayCommand(x => this.SaveObject());
  }
  return _saveCommand;
 }
}

private void SaveObject() {
 // do something
}

// XAML
{Binding Path=SaveCommand}

Nach:

// C# code
private void SaveObject() {
 // do something
}

// XAML
{BindTo SaveObject()}

Sie können die Bibliothek finden Sie hier: http://www.simplygoodcode.com/2012/ 08 / einfacherer-wpf-binding.html

Hinweis in dem ‚vor‘ Beispiel, das ich für Methode verwenden, die Code-Bindung bereits durch die Verwendung RelayCommand optimiert wurde, die ich überprüfte zuletzt ist kein nativer Teil von WPF. Ohne dass das ‚vor‘ Beispiel wäre noch länger gewesen.

Einige nützliche Bits und Stücke:

Hier ist, wie es tun vor allem in dem Code ein:

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);

ich dies weitgehend kopiert von Bindung Relative Quelle in Code Hinter .

Auch die MSDN-Seite ziemlich gut so weit wie Beispiele gehen: Relative Klasse

Ich habe gerade geschrieben eine andere Lösung für das Datacontext eines übergeordneten Elements in Silverlight zugreifen, die für mich funktioniert. Es verwendet Binding ElementName.

Ich habe nicht jede Antwort lesen, aber ich will nur diese Informationen im Fall eines relativen Quelle Befehl einer Taste Bindung hinzuzufügen.

Wenn Sie eine relative Quelle mit Mode=FindAncestor verwenden, kann die Bindung muss wie:

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"

Wenn Sie nicht über Datacontext in Ihrem Pfad hinzufügen, zum Zeitpunkt der Ausführung es die Eigenschaft nicht abrufen kann.

Dies ist ein Beispiel für die Verwendung dieses Musters, das für mich auf leere Datagrids gearbeitet.

<Style.Triggers>
    <DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
        <Setter Property="Background">
            <Setter.Value>
                <VisualBrush Stretch="None">
                    <VisualBrush.Visual>
                        <TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Setter.Value>
        </Setter>
    </DataTrigger>
</Style.Triggers>

Wenn ein Element nicht Teil der visuellen Struktur ist, dann wird Relative nie funktionieren.

In diesem Fall müssen Sie eine andere Technik, um zu versuchen, Pionierarbeit von Thomas Levesque.

Er hat die Lösung auf seinem Blog unter sein Artikel .

Bitte nicht kommentieren hier, bitte Kommentar direkt auf seiner Blog-Post .

Anhang A: Spiegel der Blog-Post

Die Datacontext-Eigenschaft in WPF ist äußerst praktisch, weil sie automatisch von allen Kindern des Elements geerbt, in dem Sie es zuweisen; deshalb brauchen Sie nicht erneut eingestellt auf jedes Element, das Sie binden möchten. In einigen Fällen jedoch, die Datacontext nicht zugänglich sind: geschieht es für Elemente, die nicht Teil der visuellen oder logischen Struktur sind. Es kann sehr schwierig sein, dann eine Eigenschaft auf die Elemente zu binden ...

Lassen Sie uns mit einem einfachen Beispiel verdeutlichen: Wir haben eine Liste von Produkten in einem Datagrid angezeigt werden soll. Im Netz wollen wir die Preisspalte angezeigt oder verborgen werden zu können, basierend auf dem Wert eines ShowPrice Eigenschaft des Ansichtsmodell ausgesetzt. Der offensichtliche Ansatz ist es, die Sichtbarkeit der Säule an die ShowPrice Eigenschaft zu binden:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding ShowPrice,
                Converter={StaticResource visibilityConverter}}"/>

Leider ist der Wert von ShowPrice Veränderung hat keine Wirkung, und die Spalte ist immer sichtbar ... warum? Wenn wir an das Ausgabefenster in Visual Studio suchen, bemerken wir die folgende Zeile:

  

System.Windows.Data Fehler: 2: Kann nicht regeln Framework oder Framework für Zielelement finden. Binding: Path = ShowPrice; DataItem = null; Zielelement ist ‚Datagridtextcolumn‘ (HashCode = 32.685.253); Zieleigenschaft ist ‚Sichtbarkeit‘ (Typ ‚Sichtbarkeit‘)

     

Die Botschaft ist ziemlich kryptisch, aber die Bedeutung ist eigentlich ganz einfach: WPF nicht weiß, welche Framework die Datacontext zu verwenden zu bekommen, weil die Spalte auf den visuellen oder logischen Baum gehört nicht des Datagrid

Wir können versuchen, die Bindung zu zwicken das gewünschten Ergebnis, zum Beispiel zu erhalten, indem die Relative an den Datagrid Einstellung selbst:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding DataContext.ShowPrice,
                Converter={StaticResource visibilityConverter},
                RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>

Oder wir können eine CheckBox in dem ShowPrice gebunden ist, und versuchen, die Spalte Sichtbarkeit auf die IsChecked Eigenschaft zu binden, indem das Element Namen angeben:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding IsChecked,
                Converter={StaticResource visibilityConverter},
                ElementName=chkShowPrice}"/>

Aber keine dieser Abhilfen scheint, arbeiten wir das gleiche Ergebnis immer bekommen ...

An diesem Punkt scheint es, dass der einzig gangbare Weg wäre, die Spalte Sichtbarkeit in Code-behind zu ändern, was wir bevorzugen in der Regel zu vermeiden, wenn das MVVM Muster mit ... Aber ich werde nicht so schnell aufgeben, zumindest nicht, während es gibt auch andere Optionen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top