I am trying to make design a WPF TreeView where the ContextMenu activates on particular nodes.
In my example, despite my best efforts, I cannot keep the ContextMenu of a BarNode from appearing when it’s children ‘FooNode’s are clicked.
C#:
public abstract class NodeBase
{
public NodeBase[] ChildNodes { get; set; }
}
public class FooNode : NodeBase
{
}
public class BarNode : NodeBase
{
}
public class ExampleModel : BaseModel
{
private NodeBase[] _nodes;
public NodeBase[] Nodes
{
get
{
_nodes = new NodeBase[]
{
new FooNode(),
new BarNode()
{
ChildNodes = new NodeBase[]
{
new FooNode(),
new FooNode()
}
}
};
return _nodes;
}
}
public ExampleModel()
{
}
}
public class TreeViewStyleSelector : StyleSelector
{
public Style FooNodeStyle { get; set; }
public Style BarNodeStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
var fooNode = item as FooNode;
if (fooNode != null)
{
return FooNodeStyle;
}
var barNode = item as BarNode;
if (barNode != null)
{
return BarNodeStyle;
}
return base.SelectStyle(item, container);
}
}
XAML
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Nodes="clr-namespace:UnderstandingWPFTreeView.Nodes"
xmlns:Models="clr-namespace:UnderstandingWPFTreeView.Models"
xmlns:Common="clr-namespace:UnderstandingWPFTreeView.Common"
x:Class="UnderstandingWPFTreeView.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<Models:ExampleModel/>
</Window.DataContext>
<Window.Resources>
<ContextMenu x:Key="testContextMenu">
<MenuItem Header="Test Context Item"></MenuItem>
<MenuItem Header="Test Context Item"></MenuItem>
</ContextMenu>
<Style TargetType="{x:Type TreeViewItem}" x:Key="FooNodeStyle">
</Style>
<Style TargetType="{x:Type TreeViewItem}" x:Key="BarNodeStyle">
<Setter Property="ContextMenu" Value="{StaticResource testContextMenu}" />
</Style>
<Common:TreeViewStyleSelector
x:Key="treeViewStyleSelector"
FooNodeStyle="{StaticResource ResourceKey=FooNodeStyle}"
BarNodeStyle="{StaticResource ResourceKey=BarNodeStyle}" />
</Window.Resources>
<StackPanel HorizontalAlignment="Left" Height="320" VerticalAlignment="Top" Width="517">
<TreeView Height="100">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type Nodes:BarNode}" ItemsSource="{Binding Path=ChildNodes}">
<TextBlock Text="Bar" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type Nodes:FooNode}" ItemsSource="{Binding Path=ChildNodes}">
<TextBlock Text="Foo" />
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeViewItem Header="Testing" ItemsSource="{Binding Nodes}" ItemContainerStyleSelector="{StaticResource ResourceKey=treeViewStyleSelector}"/>
</TreeView>
</StackPanel>
</Window>
I asked the same question of the MSDN Forums and got an answer that I can confirm as working.
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7dd183bc-d616-4ec4-8b2a-0b438c9a115c
Placing the ContextMenu objects on the TextBlock gives the same visual appearance, minus the effect of passing the ContextMenu down the chain of TreeNodes.