我有一个带有多个 HierarchicalDataTemplate&的 TreeView 。 DataTemplate 项目和我正在使用 Caliburn Micro 用于mvvm。树视图的 ItemsSource 指向视图模型中名为“TreeData”的集合,我尝试为每个HierarchicalDataTemplate&添加特定的ContextMenu。 DataTemplate中。
在ContextMenu中,我使用校准功能“ cal:Message.Attach ”来调用
中的函数我做了一个较小的树视图示例来说明问题。
在ViewModel(集合对象)中:
public class MyViewModel
{
// TreeData object
public ObservableCollection<TestRoot> TreeData = new ObservableCollection<TestRoot>()
{
new TestRoot()
{
Name = "Root item"
}
};
// the function on the viewmodel that should be called
public void DoSomething(object item)
{
MessageBox.Show("MyViewModel - DoSomething called");
}
}
集合对象:
public class TestRoot
{
public string Name { get; set; }
// caliburn calls this instead of the one on the viewmodel
public void DoSomething(object item)
{
MessageBox.Show("TestRoot - DoSomething called");
}
}
MyView.xaml treeview只有一个(Hierarchical)DataTemplate:
<TreeView Margin="5" ItemsSource="{Binding TreeData}">
<TreeView.Resources>
<DataTemplate DataType="{x:Type vm:TestRoot}" >
<StackPanel Orientation="Horizontal">
<StackPanel.ContextMenu>
<ContextMenu>
<!-- caliburn (?) chooses the method on the collection object, not the viewmodel -->
<MenuItem Header="test dosomething" cal:Message.Attach="DoSomething($dataContext)"></MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
在另一段代码中,我将ContextMenu放在TreeView.ContextMenu中。它在'应该'工作,指向viewmodel上的方法。
寻找解决方案,我看到“继承上下文”之类的东西。我认为它可能与它有关,但我不确定。我如何告诉caliburn它必须在我的方法的viewmodel中查找,而不是我点击的TreeView中的项目?
或者还有其他可能吗?例如:在Resources中定义不同的ContextMenus并将它们指向DataTemplates?但是,这不会导致完全相同的问题吗?
请注意,我希望尽可能减少代码隐藏。感谢
更新
为了完整性,这是真正的开发代码。这应该是对的,不是吗?
<TreeView ItemsSource="{Binding OrderTreeViewData.OrderTreeViewCategories}"
cal:Message.Attach="[Event SelectedItemChanged] = [Action OnSelectedItemChanged($this)]">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- We have to select the item which is right-clicked on -->
<EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown"
Handler="TreeViewItem_PreviewMouseRightButtonDown"/>
<!-- set expanded -->
<Setter Property="TreeViewItem.IsExpanded" Value="True"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<!-- dredge nodes -->
<HierarchicalDataTemplate DataType="{x:Type programs:DredgeRoot}"
ItemsSource="{Binding Dredgezones}">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add dredge zone" cal:Message.Attach="TreeViewAddDredgeZone($datacontext)"></MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
<!-- omitted other templates -->
</TreeView.Resources>
</TreeView>
答案 0 :(得分:0)
不幸的是,还有一个棘手的问题需要处理。由于特定的Popup
行为,它不会继承DataContext
。要访问正确的上下文,您必须获得PlacementTarget
:
<StackPanel Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="test dosomething" cal:Message.Attach="DoSomething"/>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
答案 1 :(得分:0)
我认为你和我有几乎相同的问题,也许可以看到这个主题:Bind contextMenu to a different viewmodel from treeview
您可以尝试使用命令: 尝试将您的代码更改为:
<ContextMenu x:Key="MyContextMenu">
<MenuItem Header="Add dredge zone" Command="{Binding PlacementTarget.Tag.DataContext.TreeViewAddDredgeZoneCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"
CommandParameter="{Binding}"></MenuItem>
</ContextMenu>
然后将hierarchyDataTemplate添加到Tag和ContextMenu
<HierarchicalDataTemplate DataType="{x:Type programs:DredgeRoot}"
ItemsSource="{Binding Dredgezones}" Tag="{Binding RelativeSource={RelativeSource AncestorType=UserControl}} ContextMenu="{StaticResource MyContextMenu}">
在您的viewmodel中,您可以使用以下内容添加命令:
public ICommand TreeViewAddDredgeZoneCommand
{
//your code here
}