Question

I have a user control with a TreeView where the nodes are generated dinamically (in fact I use the HierarchicalDataTemplate property), depending on the structure of an input XML. If I click with the left button on the single node, the content of that part of XML appears on a separate user control. The single node is visualized through the property Header of a TreeViewItem.

What I would like to add, is a logic with the right button that simply shows a contextual menu with few commands on that single node.

I searched for some material online (as I'm quite new to WPF) and tried first to define a context Menu...

1st solution XAML:

<TreeView x:Name="treeViewStruttura" Panel.ZIndex="1" HorizontalAlignment="Left" VerticalContentAlignment="Top" Width="200" Height="Auto">
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
      <HierarchicalDataTemplate.Resources>
        <Style TargetType="{x:Type TreeViewItem}">
          <EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnTreeNodeMouseClick" />
          <EventSetter Event="PreviewMouseRightButtonDown" Handler="OnTreeNodeMouseRightClick"/>
          <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
              <Setter Property="BorderBrush" Value="LightGray" />
            </Trigger>
          </Style.Triggers>
          <Style.Resources>
            <Style TargetType="Border">
              <Setter Property="CornerRadius" Value="4"/>
              <Setter Property="BorderThickness" Value="4"/>
            </Style>
          </Style.Resources>
        </Style>
      </HierarchicalDataTemplate.Resources>
      <TreeViewItem Header="{Binding Text}" x:Name="treeViewItem" HorizontalAlignment="Left" HorizontalContentAlignment="Left"
                BorderThickness="2">
        <TreeViewItem.ContextMenu>
            <ContextMenu IsEnabled="True" IsOpen="True" >
              <MenuItem Command="ModificaArticolo"  />
              <MenuItem x:Name="menuItemCopy" Header="Copy" Command="Copy" Tag="0"/>
            </ContextMenu>
          </TreeViewItem.ContextMenu>
      </TreeViewItem>
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>
</TreeView>

Codebehind:

public partial class DocumentView : UserControl
{
    public DocumentView()
    {
        InitializeComponent();
        PreviewMouseRightButtonDown += DocumentView_PreviewMouseRightButtonDown;

    }

    void DocumentView_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        MenuClick();
    }

    private void MenuClick()
    {
        ContextMenu menu = new ContextMenu();

        var copyMenuItem = new MenuItem();
        copyMenuItem.Command = System.Windows.Input.ApplicationCommands.Copy;
        copyMenuItem.Header = "Copy";
        menu.Items.Add(copyMenuItem);
        menu.Visibility = System.Windows.Visibility.Visible;

        menu.IsEnabled = true;
        menu.IsOpen = true;
        menu.Focusable = true;
    }
}

Second solution, I tried to define a Context Menu outside the XAML TreeView:

<ContextMenuService.ContextMenu>
        <ContextMenu x:Name="contextMenuTreeViewItem">
            <Style TargetType="{x:Type TreeViewItem}" >
            </Style>
            <MenuItem x:Name="menuItemCopy" Header="Copy" Command="Copy" Tag="0"/>
        </ContextMenu>
</ContextMenuService.ContextMenu>

CodeBehind:

private void MenuClick()
{
    this.contextMenuTreeViewItem.IsOpen = true;
    this.contextMenuTreeViewItem.IsEnabled = true;
    this.menuItemCopy.IsEnabled = true;
    this.contextMenuTreeViewItem.StaysOpen = true;
}

I'm sure I'm doing something wrong but I can't say what precisely...plus I saw the use of property ContextMenu as a Setter Property...and I can't appreciate the differences on this approach.

Thx in advance for your help.

Was it helpful?

Solution

This comes years later but given that no answer was proposed, perhaps someone may benefit from this. What has worked for me is to define a context menu in the TreeView.Resources section and give it a key for identification, as follows:

        <TreeView.Resources>
            <ContextMenu x:Key="ChildContextMenu">
                <MenuItem Header="View"/>
                <MenuItem Header="Edit"/>
                <MenuItem Header="Print"/>
                <MenuItem Header="Delete"/>
                <MenuItem Header="Batch actions">
                    <MenuItem Header="View all"/>
                    <MenuItem Header="Edit all"/>
                    <MenuItem Header="Print all"/>
                    <MenuItem Header="Delete all"/>
                </MenuItem>
            </ContextMenu>
        </TreeView.Resources>

The above context menu can then be attached to whichever control used as a TreeViewItem, as follows (here I set the context menu on the TextBlock):

        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:Sample}" ItemsSource="{Binding Path=Children}">
                <TextBlock Text="{Binding Path=Parent}"/>
                <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Name}" ContextMenu="{StaticResource ChildContextMenu}"/>
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>

The complete code becomes:

<TreeView>
            <TreeView.Resources>
                <ContextMenu x:Key="ChildContextMenu">
                    <MenuItem Header="View"/>
                    <MenuItem Header="Edit"/>
                    <MenuItem Header="Print"/>
                    <MenuItem Header="Delete"/>
                    <MenuItem Header="Batch actions">
                        <MenuItem Header="View all"/>
                        <MenuItem Header="Edit all"/>
                        <MenuItem Header="Print all"/>
                        <MenuItem Header="Delete all"/>
                    </MenuItem>
                </ContextMenu>
            </TreeView.Resources>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Sample}" ItemsSource="{Binding Path=Children}">
                    <TextBlock Text="{Binding Path=Parent}"/>
                    <HierarchicalDataTemplate.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Name}" ContextMenu="{StaticResource ChildContextMenu}"/>
                        </DataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
</TreeView>

The logic to handle clicks can be attached in various ways, one of them being per MenuItem. I hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top