Reputation: 2409
I'm dynamically generating a tree (TreeViewItem
s) and want to add the same context menu to each item in the tree. Because all of the context menus will be the same, I figured I could make one, and apply it to each TreeViewItem
. (Maybe this is a bad idea?) Seems like this should work as long as the Click
handler can figure out which TreeViewItem
's context menu was opened.
I tried combining SO answers from here (getting the right-clicked object) and here (programmatically adding a binding) and came up with this:
ContextMenu carContextMenu;
public MainWindow()
{
InitializeComponent();
Initialize();
ConstructTree();
}
void ConstructTree()
{
string[] carNames = {"Mustang", "Viper", "Jetta"};
foreach (string car in carNames)
{
TreeViewItem carNode = new TreeViewItem();
carNode.Header = car;
carNode.ContextMenu = carContextMenu;
CarTree.Items.Add(carNode);
}
}
void Initialize()
{
carContextMenu= new ContextMenu();
MenuItem newQuery = new MenuItem();
newQuery.Header = "Drive car...";
Binding b = new Binding("Parent");
b.RelativeSource = RelativeSource.Self;
newQuery.SetBinding(MenuItem.CommandParameterProperty, b);
newQuery.Click += NewQuery_Click;
carContextMenu.Items.Add(newQuery);
}
void NewQuery_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.CommandParameter as ContextMenu; // *****
if (cm != null)
{
TreeViewItem node = cm.PlacementTarget as TreeViewItem;
if (node != null)
{
Console.WriteLine(node.Header); // car name, ideally
}
}
}
}
At runtime, when it gets to the line with asterisks, mi.CommandParameter
is null, so it skips the rest of the method. What's going on with my approach? Honestly, I'm a little surprised that the right-clicked item isn't an intrinsic part of the event handler arguments, given how often you'd want to know what was clicked. Tree items aren't necessary selected when they're right-clicked, so checking that isn't a reliable method... plus it'd just be a hacky workaround.
Thanks!
Upvotes: 5
Views: 9304
Reputation: 2409
Naturally, it turns out I was overcomplicating things and the links I was following were either incorrect, out-of-date, or (most likely) I misread some portion of their scenario and there was something that didn't actually apply to me.
I didn't need any Binding on the MenuItem
itself and simply should have been looking at myMenuItem.Parent.PlacementTarget
the whole time. Working code below:
void Initialize()
{
carContextMenu= new ContextMenu();
MenuItem newQuery = new MenuItem();
newQuery.Header = "Drive car...";
newQuery.Click += NewQuery_Click;
carContextMenu.Items.Add(newQuery);
}
void NewQuery_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = sender as MenuItem;
if (mi != null)
{
ContextMenu cm = mi.Parent as ContextMenu;
if (cm != null)
{
TreeViewItem node = cm.PlacementTarget as TreeViewItem;
if (node != null)
{
Console.WriteLine(node.Header);
}
}
}
}
Upvotes: 3