Creating dynamic ContextMenu for TreeView in WPF

Hi,

Sharing a simple example wherein we are generating dynamic menuitems for the context menu based on the node or treeviewitem selected in the treeview.

If root Packages is selected –

If Package is selected –

If Batch is selected –

The xml file

<?xml version="1.0" encoding="utf-8" ?>
<Packages>
 <Package Name="Package 1" Type="Package">
 <Batch Name="Batch 1" Type="Batch"/>
 <Batch Name="Batch 2" Type="Batch"/>
 </Package>
 <Package Name="Package 2" Type="Package">
 <Batch Name="Batch 1" Type="Batch"/>
 <Batch Name="Batch 2" Type="Batch"/>
 </Package>
</Packages>

XAML

<Window x:Class="SampleSyncServerAdminTool.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>
 <!--Binding TreeView-->
 <XmlDataProvider x:Key="MyList" Source="Packages.xml" XPath="Packages"/>

<HierarchicalDataTemplate DataType="Packages" ItemsSource="{Binding XPath=*}">
 <TextBlock Text="Packages"></TextBlock>
 </HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="Package" ItemsSource="{Binding XPath=*}">
 <TextBlock Text="{Binding XPath=@Name}"></TextBlock>
 </HierarchicalDataTemplate>

<HierarchicalDataTemplate DataType="Batch" ItemsSource="{Binding XPath=*}">
 <TextBlock Text="{Binding XPath=@Name}"></TextBlock>
 </HierarchicalDataTemplate>

<!-- Resources for Right Hand Side detail grid-->

<DataTemplate x:Key="ClosableTabItemTemplate">
 <DockPanel Width="120">
 <Button
 Command="{Binding Path=CloseCommand}"
 Content="X"
 Cursor="Hand"
 DockPanel.Dock="Right"
 Focusable="False"
 FontFamily="Courier"
 FontSize="9"
 FontWeight="Bold"
 Margin="0,1,0,0"
 Padding="0"
 VerticalContentAlignment="Bottom"
 Width="16" Height="16"
 />
 <ContentPresenter
 Content="{Binding Path=DisplayName}"
 VerticalAlignment="Center"
 />
 </DockPanel>
 </DataTemplate>

<DataTemplate x:Key="WorkspacesTemplate">
 <TabControl
 IsSynchronizedWithCurrentItem="True"
 ItemsSource="{Binding}"
 ItemTemplate="{StaticResource ClosableTabItemTemplate}"
 Margin="4"
 />
 </DataTemplate>

</Window.Resources>
 <Grid>
 <DockPanel>
 <TreeView DockPanel.Dock="Left" Width="150" Name="treeViewPackages"

 ItemsSource="{Binding Source={StaticResource MyList}}">
 <TreeView.Resources>
 <ContextMenu x:Key="TestMenu">
 </ContextMenu>
 </TreeView.Resources>
 <TreeView.ItemContainerStyle>
 <Style TargetType="{x:Type TreeViewItem}">
 <Setter Property="IsExpanded" Value="True"/>
 <EventSetter Event="PreviewMouseRightButtonDown"
 Handler="OnPreviewMouseRightButtonDown" />
 </Style> </TreeView.ItemContainerStyle>
 </TreeView>
 <Grid DockPanel.Dock="Right">
 <HeaderedContentControl
 Content="{Binding Path=Workspaces}"
 ContentTemplate="{StaticResource WorkspacesTemplate}"
 Header="Workspaces"
 />
 </Grid>
 </DockPanel>
 </Grid>
</Window>

XAML.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;

namespace SampleSyncServerAdminTool
{
 /// <summary>
 /// Interaction logic for MainWindow.xaml
 /// </summary>
 public partial class MainWindow : Window
 {
 public MainWindow()
 {
 InitializeComponent();
 }

void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
 {

DependencyObject obj = e.OriginalSource as DependencyObject;
 TreeViewItem item = GetDependencyObjectFromVisualTree(obj, typeof(TreeViewItem)) as TreeViewItem;
 XmlElement selectedElement = (XmlElement)item.Header;

string header = selectedElement.Name;
 if (header.ToUpper() == "PACKAGES")
 {
 // Packages root node
 MenuItem mnuItem = new MenuItem();
 mnuItem.Header = "New Package";
 ContextMenu menu = new ContextMenu() { };
 menu.Items.Add(mnuItem);
 (sender as TreeViewItem).ContextMenu = menu;
 }

else
 {
 string attName = selectedElement.Attributes["Name"].Value;
 string type = selectedElement.Attributes["Type"].Value;

string fullNodeInfo = "Header: " + header + " Attribute Name: " + attName + " Type: " + type;

if (type.ToUpper() == "PACKAGE")
 {
 MenuItem mnuItem1 = new MenuItem();
 mnuItem1.Header = "New Package";
 MenuItem mnuItem2 = new MenuItem();
 mnuItem2.Header = "Show Package Details";
 MenuItem mnuItem3 = new MenuItem();
 mnuItem3.Header = "Edit Package";
 MenuItem mnuItem4 = new MenuItem();
 mnuItem4.Header = "Delete Package";
 MenuItem mnuItem5 = new MenuItem();
 mnuItem5.Header = "Add to Queue";

ContextMenu menu = new ContextMenu() { };
 menu.Items.Add(mnuItem1);
 menu.Items.Add(mnuItem2);
 menu.Items.Add(mnuItem3);
 menu.Items.Add(mnuItem4);
 menu.Items.Add(mnuItem5);

(sender as TreeViewItem).ContextMenu = menu;
 }
 else if (type.ToUpper() == "BATCH")
 {
 MenuItem mnuItem1 = new MenuItem();
 mnuItem1.Header = "Show Batch Details";
 MenuItem mnuItem2 = new MenuItem();
 mnuItem2.Header = "Edit Batch";
 MenuItem mnuItem3 = new MenuItem();
 mnuItem3.Header = "Delete Batch";

ContextMenu menu = new ContextMenu() { };
 menu.Items.Add(mnuItem1);
 menu.Items.Add(mnuItem2);
 menu.Items.Add(mnuItem3);

(sender as TreeViewItem).ContextMenu = menu;
 }
 }
 }

private static DependencyObject GetDependencyObjectFromVisualTree(DependencyObject startObject, Type type)
 {
 var parent = startObject;
 while (parent != null)
 {
 if (type.IsInstanceOfType(parent))
 break;
 parent = VisualTreeHelper.GetParent(parent);
 }
 return parent;
 }
 }
}

Bye.


Author: Nishant Rana

I love working in and sharing everything about Microsoft.NET technology !

4 thoughts on “Creating dynamic ContextMenu for TreeView in WPF”

  1. This is a good example, except that it doesn’t show how to handle the command binding of a dynamically generated ContextMenu for a TreeViewItem.

    Like

  2. “(sender as TreeViewItem).ContextMenu = menu;” can throw a null reference exception. Use “item.ContextMenu=menu;” instead. You should also check to see if item is null and if so, return before attempting to do anything further,

    Like

  3. Hi, can you upload or send me the project? I trying to load the Packages.xml with his Packages, Package and Batch classes but its not worked. I will appreciate it.

    Thank you!

    Like

Share your thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s