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

je travaille actuellement dans un contrôle d'utilisateur WPF (l'élément racine de mon fichier XAML est "UserControl"), dont je sais qu'il est hébergé dans une fenêtre. Comment puis-je accéder à une propriété de la fenêtre en utilisant data binding?

Est-ce que quelqu'un sait pourquoi simplement

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

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

Système.Windows.Avertissement de données: 4: Impossible de trouver la source pour la liaison avec la référence 'RelativeSource FindAncestor, AncestorType=' système.Windows.Fenêtre", Niveau d'ancêtre= '1".

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

21
demandé sur user200783 2009-10-28 14:56:30

3 réponses

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

Créer une dépendance de la propriété MyProperty dans UserControl avec une liaison bidirectionnelle et à l'engager dans la Fenêtre principale, que lient dans UserControl comme ceci

<UserControl x:Name = "myControl">
     <Label Content={Binding ElementName= myControl, Path=MyProperty}/>
</UserControl>
17
répondu Arsen Mkrtchyan 2009-10-28 12:12:52

si vous essayez de "vous échapper" d'un ItemsControl ou DataGridView pour obtenir un Window vous pouvez peut-être trouver que AncestorType de x:Type Window ne fonctionne pas. Ou au moins ne semble pas...

si c'est le cas, vous utilisez probablement Blend ou Visual Studio et vous attendez à ce que les données soient visibles au moment de la conception - ce qui n'est pas le cas parce que VS + Blend crée leurs propres instances qui ne sont pas vraiment des fenêtres. Il fonctionnera à l'exécution tout simplement bien, mais pas pendant la conception mode.

Il ya un couple de choses que vous pouvez faire:

  • Enveloppez-les dans un UserControl

  • Voici une solution alternative que j'ai trouvé. Il a un avantage en ce que vous ne faites pas référence à un UserControl ou Window directement, 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
   {

   }
}

puis quand vous liez pour ce faire :

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

Note: Si vous voulez lier une propriété sur la fenêtre elle-même, c'est plus compliqué et vous devriez probablement le faire via une propriété de dépendance ou quelque chose comme ça. Mais si vous utilisez MVVM alors c'est une solution que j'ai trouvé.

4
répondu Simon_Weaver 2011-11-16 05:20:05

je Pense que Vous Devriez mettre en Mode="OneWayToSource" Comme ceci:

<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor ,AncestorType={x:Type Grid}},Path=BackGround , Mode=OneWayToSource , UpdateSourceTrigger = PropertyChanged}" />
1
répondu MahmudReza Tari 2011-09-21 13:13:25