web-dev-qa-db-fra.com

Que fait exactement "RelativeSource FindAncestor" de WPF Data Binding?

Je travaille actuellement au sein d'un contrôle utilisateur WPF (l'élément racine de mon fichier XAML est "UserControl"), qui, je le sais, est hébergé dans une fenêtre. Comment puis-je accéder à une propriété de la fenêtre à l'aide de la liaison de données?

Est-ce que quelqu'un sait pourquoi tout simplement

<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="..." />

ne marche pas? Le message d'erreur que je reçois est:

System.Windows.Data Avertissement: 4: Impossible de trouver la source de liaison avec la référence 'RelativeSource FindAncestor, AncestorType =' System.Windows.Window ', AncestorLevel =' 1 ''.

Edit: J'ai fini par utiliser une variante de l'approche d'ArsenMkrt, j'ai donc accepté sa réponse. Cependant, je suis toujours intéressé à découvrir pourquoi FindAncestor ne "fonctionne pas seulement".

21
user200783

La meilleure façon est de donner un nom à UserControl

Créer la propriété de dépendance MyProperty dans UserControl avec une liaison bidirectionnelle et la lier dans la fenêtre principale, puis la lier dans UserControl comme ceci

<UserControl x:Name = "myControl">
     <Label Content={Binding ElementName= myControl, Path=MyProperty}/>
</UserControl>
18
Arsen Mkrtchyan

Si vous essayez de "vous échapper" d'un ItemsControl ou DataGridView pour accéder à un Window, vous constaterez peut-être que AncestorType de x:Type Window ne fonctionne pas. Ou du moins ne semble pas ...

Si tel est le cas, vous exécutez probablement Blend ou Visual Studio et vous attendez à ce que les données soient visibles au moment de la conception - ce qui ne sera pas le cas, car VS + Blend créent tous deux leurs propres instances qui ne sont pas vraiment Windows. Cela fonctionnera très bien au moment de l'exécution, mais pas en mode conception.

Vous pouvez faire quelques choses:

  • Envelopper dans un UserControl

  • Voici une solution alternative que j'ai trouvée. Il présente un avantage en ce que vous ne faites pas directement référence à un UserControl ou Window, donc si vous changez le conteneur parent, votre code ne se cassera pas.

    <Window
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.Microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="clr-namespace:MyWPFApplication.Views"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"                  
    x:Class="MyWPFApplication.Views.UPCLabelPrinterWindow"
    mc:Ignorable="d"
    x:Name="LayoutRoot"
    Title="UPCLabelPrinterWindow">
    
    <views:DataContextWrapper>
        <DockPanel>
            ...
        </DockPanel>
    </views:DataContextWrapper>
    

DataContextWrapper est juste une grille

namespace MyWPFApplication.Views {
   public class DataContextWrapper : Grid
   {

   }
}

Ensuite, lorsque vous vous liez, faites ceci:

<TextBlock Text="{Binding="{Binding DataContext.SomeText, 
  RelativeSource={RelativeSource AncestorType={x:Type views:DataContextWrapper}, 
  Mode=FindAncestor}}" />

Remarque: si vous souhaitez vous lier à une propriété sur la fenêtre elle-même, c'est plus difficile et vous devriez probablement vous lier via une propriété de dépendance ou quelque chose comme ça. Mais si vous utilisez MVVM, c'est une solution que j'ai trouvée.

4
Simon_Weaver

Je pense que vous devriez définir Mode = "OneWayToSource" comme ceci:

<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor ,AncestorType={x:Type Grid}},Path=BackGround , Mode=OneWayToSource , UpdateSourceTrigger = PropertyChanged}" />
1
MahmudReza Tari