Hello,
We need to create an MVVM solution for tree view control with context menu. The context menu has to be different for each node, based on the type of the node.
We have tried the following approach: binding the context menu items to given properties of the XamDataTree's ItemSource.
<ig:XamDataTree x:Name="customerGroupTreeView"
ActiveNodeChanged="customerGroupTreeViewProjects_ActiveNodeChanged"
ItemsSource="{Binding TreeViewCustomersGroup}"
BorderThickness="0">
<ig:XamDataTree.ContextMenu>
<ContextMenu Loaded="ContextMenu_Loaded">
<MenuItem Header="New"
IsEnabled="{Binding Data.IsNew}">MenuItem>
ContextMenu>
ig:XamDataTree.ContextMenu>
<ig:XamDataTree.EditingSettings>
<ig:TreeEditingSettings AllowDeletion="{Binding AllowDeletion}"
AllowEditing="{Binding AllowEditing}" />
ig:XamDataTree.EditingSettings>
<ig:XamDataTree.Resources>
<DataTemplate x:Key="NodeDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20">ColumnDefinition>
<ColumnDefinition>ColumnDefinition>
Grid.ColumnDefinitions>
<Image Grid.Column="0"
Height="16"
Width="16"
Source="{Binding Data.ImagePath}">
Image>
<TextBlock Text="{Binding Data.Name}"
Margin="5,0,0,0"
Grid.Column="1" />
Grid>
DataTemplate>
ig:XamDataTree.Resources>
<ig:XamDataTree.SelectionSettings>
<ig:TreeSelectionSettings NodeSelection="Single" />
ig:XamDataTree.SelectionSettings>
<ig:XamDataTree.GlobalNodeLayouts>
<ig:NodeLayout Key="MyNode"
TargetTypeName="Node"
ItemTemplate="{StaticResource NodeDataTemplate}">
ig:NodeLayout>
ig:XamDataTree.GlobalNodeLayouts>
ig:XamDataTree>
1. This binding isn't working. Can you please give an example of how the contextmenu would be bound to the Node data?
2. Also, we would like the Node which the user has right clicked on to be the selected node. How can we implement this?
Thanks!
DVSE Team
Hi Darrel,I've tried to follow your suggestion (looks great!) but when I set IsActive property, menu disappears...Any ideas? This is the full code:
<TextBlock.ContextMenu> <ContextMenu IsVisibleChanged="ContextMenu_IsVisibleChanged" Tag="{Binding Node}"> <MenuItem Header="Collapse" Command="{x:Static my:Control.collapseCommand}" /> </ContextMenu> </TextBlock.ContextMenu>
private void ContextMenu_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { ContextMenu menu = sender as ContextMenu; if (menu != null && menu.IsVisible) { XamDataTreeNode nd = menu.Tag as XamDataTreeNode; if (nd != null) { nd.IsActive = true; } } }
Thank you, bye. Maria
Hi Darrel,
The solution you suggested works perfectly.
Thanks for your help!
1) You set your context menu on the tree object, not on a node object. So the context menu would only have the properties available at that level.
You would probably want to set up the ItemTemplate off the NodeLayout to be something like this.
<ig:NodeLayout Key="blah" DisplayMemberPath="Name" TargetTypeName="Person"> <ig:NodeLayout.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Data.Name}"> <TextBlock.ContextMenu> <ContextMenu> <MenuItem Header="New" IsEnabled="{Binding Data.IsEnabled}" ></MenuItem> </ContextMenu> </TextBlock.ContextMenu> </TextBlock> </DataTemplate> </ig:NodeLayout.ItemTemplate></ig:NodeLayout>
As for how to activate the node which is right clicked. You would have to react to the right mouse down somehow and set the node to be the active node. One way you could try doing this is listening to when the context menu is opening and then have the information available to set the node active
<TextBlock.ContextMenu> <ContextMenu IsVisibleChanged="ContextMenu_IsVisibleChanged" Tag="{Binding Node}" > <MenuItem Header="New" IsEnabled="{Binding Data.IsEnabled}" ></MenuItem> </ContextMenu> </TextBlock.ContextMenu>
private void ContextMenu_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { // if the context menu is now visible
// check the Tag property of the context menu (the sender object)
// get the node out of the Tag and set the IsActive flag }