4

I have a DataTemplate within my Window's Resources section that creates a TextBlock with a ContextMenu. I want to be able to set whether a MenuItem within the ContextMenu is visible from within my Window's view model. I have tried accessing the DataContext of the Window by setting ElementName, and also tried setting RelativeSource, but both approaches resulted in binding errors. I'm not sure what else I can try.

I have created a small example that shows what I'm trying to do:

XAML:

<Window x:Class="DataTemplateTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <ResourceDictionary> <DataTemplate x:Key="TestDataTemplate"> <TextBlock Text="{Binding}"> <TextBlock.ContextMenu> <ContextMenu> <MenuItem Header="Test" Visibility="{Binding Path=DataContext.MenuItemVisible, ElementName=Root}"/> </ContextMenu> </TextBlock.ContextMenu> </TextBlock> </DataTemplate> </ResourceDictionary> </Window.Resources> <ScrollViewer x:Name="Root"> <ItemsControl ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource TestDataTemplate}" /> </ScrollViewer> 

Code behind:

using System.Collections.Generic; using System.ComponentModel; using System.Windows; namespace DataTemplateTest { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { protected readonly MainWindowViewModel vm; public MainWindow() { InitializeComponent(); vm = new MainWindowViewModel(); DataContext = vm; } } public class MainWindowViewModel : INotifyPropertyChanged { private Visibility menuItemVisible = Visibility.Hidden; public Visibility MenuItemVisible { get { return menuItemVisible; } set { menuItemVisible = value; NotifyPropertyChanged("MenuItemVisible"); } } public List<string> Items { get; set; } public MainWindowViewModel() { Items = new List<string>() { "Alpha", "Beta", "Gamma" }; } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 

The error I get is

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Root'. BindingExpression:Path=DataContext.MenuItemVisible; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Visibility' (type 'Visibility')

When I set RelativeSource instead of ElementName in the binding:

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollViewer}} 

I get the following error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ScrollViewer', AncestorLevel='1''. BindingExpression:Path=DataContext.MenuItemVisible; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Visibility' (type 'Visibility')

1 Answer 1

5

I have found the answer here:

So all I had to do to access the window's DataContext was set:

Source={x:Reference Name=Root} 

An explanation of why ElementName does not work in this case is found here. Specifically:

Probably the simplest example of where we don't have inheritance context links is across > random property elements:

<Button> <Button.ContextMenu> <ContextMenu/> </Button.ContextMenu> </Button> 

ContextMenu is neither a visual nor logical child of Button, nor is it one of the inheritance context cases listed above (ContextMenu is not a Freezable).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot man!! Only your solution worked for me.. the other RelativeSource-Stuff didn't work at all!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.