External ownership within a WPT DataTemplate

Scenario: I have a ListBox and ListBoxItems has a DataTemplate. I want to make ContextMenu in a DataTemplate. The trick is that I want this ContextMenu ItemsSource item to differ based on certain properties in the window. My initial thought is that I can just bind the ItemsSource to the Property in the window and this will return the ItemSource; however, I cannot bind to this property correctly. I believe that this is because I am in a DataTemplate, and therefore the DataContext (I believe that this is the right word) refers to this ListBoxItem, not the window. How can I get a ContextMenu inside a DataTemplate to bind to a property outside of a DataTemplate.

+4
source share
2 answers

You can get a DataContext from your window using the RelativeSource FindAncestor syntax

<DataTemplate> <TextBlock Text="{Binding MyInfo}"> <TextBlock.ContextMenu> <Menu ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MyContextMenuItems}"/> </TextBlock.ContextMenu> </TextBlock> </DataTemplate> 

Not quite sure, but the binding is correct ... If your DataContext is a different type of object, you just need to change AncestorType (e.g. UserControl).

+5
source

This may be a good candidate for AttachedProperty . Basically, what would you do is wrap ContextMenu in UserControl and then add the dependency property to UserControl. For instance:

MyContextMenu.xaml

 <UserControl x:Class="MyContextMenu" ...> <UserControl.Template> <ContextMenu ItemSource="{Binding}" /> </UserControl.Template> </UserControl> 

MyContextMenu.xaml.cs

 public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.RegisterAttached( "MenuItemsSource", typeof(Object), typeof(MyContextMenu), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender) ); public static void SetMenuItemsSource(UIElement element, Boolean value) { element.SetValue(MenuItemsSourceProperty, value); // assuming you want to change the context menu when the mouse is over an element. // use can use other events. ie right mouse button down if its a right click menu. // you may see a perf hit as your changing the datacontext on every mousenter. element.MouseEnter += (s, e) => { // find your ContextMenu and set the DataContext to value var window = element.GetRoot(); var menu = window.GetVisuals().OfType<MyContextMenu>().FirstOrDefault(); if (menu != null) menu.DataContext = value; } } public static Object GetMenuItemsSource(UIElement element) { return element.GetValue(MenuItemsSourceProperty); } 

Window1.xaml

 <Window ...> <Window.Resources> <DataTemplate TargetType="ListViewItem"> <Border MyContextMenu.MenuItemsSource="{Binding Orders}"> <!-- Others --> <Border> </DataTemplate> </Window.Resources> <local:MyContextMenu /> <Button MyContextMenu.MenuItemsSource="{StaticResource buttonItems}" /> <ListView ... /> </Window> 

VisualTreeHelpers

 public static IEnumerable<DependencyObject> GetVisuals(this DependencyObject root) { int count = VisualTreeHelper.GetChildrenCount(root); for (int i = 0; i < count; i++) { var child = VisualTreeHelper.GetChild(root, i); yield return child; foreach (var descendants in child.GetVisuals()) { yield return descendants; } } } public static DependencyObject GetRoot(this DependencyObject child) { var parent = VisualTreeHelper.GetParent(child) if (parent == null) return child; return parent.GetRoot(); } 

This example has not been verified. I will look later tonight and make sure it is accurate.

+2
source

All Articles