2011-04-25 5 views
4

Je me demande comment puis-je lier MenuItem.Header à la propriété de dépendance parent/UserControl parent? Voici un exemple simple:Comment lier MenuItem.Header à la propriété de dépendance Window/UserControl?

Window1.xaml:

<Window x:Class="WpfApplication1.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Title="Window1" Height="300" Width="300" x:Name="self"> 
    <Grid> 
     <Grid.ContextMenu> 
      <ContextMenu> 
       <MenuItem Header="{Binding Path=MenuText, ElementName=self}" /> 
      </ContextMenu> 
     </Grid.ContextMenu> 
     <TextBlock Text="{Binding Path=MenuText, ElementName=self}"/> 
    </Grid> 
</Window> 

Window1.xaml.cs:

public partial class Window1 : Window { 
    public static readonly DependencyProperty MenuTextProperty = DependencyProperty.Register(
     "MenuText", typeof (string), typeof (Window1), new PropertyMetadata("Item 1")); 

    public Window1() 
    { 
     InitializeComponent(); 
    } 

    public string MenuText { 
     get { return (string)this.GetValue(MenuTextProperty); } 
     set { this.SetValue(MenuTextProperty, value); } 
    } 
} 

Dans mon cas, affiche TextBlock "de l'article 1", et le menu contextuel affiche l'élément vide. Qu'est-ce que je fais mal? Il me semble que j'ai dû faire face à de sérieux malentendus sur les principes de la liaison de données WPF.

Répondre

7

Vous devriez voir ceci dans la fenêtre de sortie de Visual Studio:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=self'. BindingExpression:Path=MenuText; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Header' (type 'Object')

C'est parce que le ContextMenu est déconnecté du VisualTree, vous devez faire cette liaison différemment.

Une façon est par ContextMenu.PlacementTarget (qui devrait être la grille), vous pouvez utiliser son DataContext pour établir une liaison, par exemple:

<MenuItem Header="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext.MenuText}"/> 

ou mettre en place le DataContext dans le ContextMenu lui-même:

<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}"> 
    <MenuItem Header="{Binding Path=MenuText}"/> 
</ContextMenu> 

Si ce n'est pas une option (parce que le DataContext de la grille ne peut pas être le Window/UserControl) vous pouvez essayer de passer la référence à Window/UserControl par le Tag de votre Grid par exemple.

<Grid ... 
     Tag="{x:Reference self}"> 
    <Grid.ContextMenu> 
     <!-- The DataContext is now bound to PlacementTarget.Tag --> 
     <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.Tag}"> 
      <MenuItem Header="{Binding Path=MenuText}"/> 
     </ContextMenu> 
    ... 

Comme un côté note: En raison de ce comportement, j'ai tendance à définir un style d'aide à App.xaml pour faire tous les ContextMenus "pseudo-inherit" DataContext de leurs parents:

<!-- Context Menu Helper --> 
    <Style TargetType="{x:Type ContextMenu}"> 
     <Setter Property="DataContext" Value="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/> 
    </Style> 
+0

Pourriez-vous s'il vous plaît clarifier comment passer la référence à la fenêtre/UserControl à travers le Tag? Si j'utilise la syntaxe Tag = "{x: Reference self}", j'obtiens une erreur de compilation ** "La balise 'Reference' n'existe pas dans l'espace de noms XML 'http://schemas.microsoft.com/winfx/2006/xaml' . ** J'utilise VS2008 et .NET framework 3.5 –

+0

Existe seulement dans .NET 4, vous devriez pouvoir utiliser une liaison à la place, quelque chose comme 'Tag =" {Binding ElementName = self} "' –

+0

Clear.Thanks beaucoup –

Questions connexes