Caliburn.micro 通过 contextmenu onclick 获取 treeview 的选中项
Caliburn.micro get treeview's selected item by contextmenu onclick
我的任务是在树视图中使用上下文菜单,并通过单击上下文菜单元素将所选树视图的项目传递给 ViewModel。
这是我的 xaml:
<Window.Resources>
<HierarchicalDataTemplate x:Key="Ufps"
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" />
<TextBlock Margin="5 0 0 0" Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
........
........
<TreeView x:Name="TrvUfpsDictionary" Height="222" Canvas.Left="25"
Canvas.Top="280" Width="545"
Background="AliceBlue"
ItemsSource="{Binding Path=Ufps, Mode=OneWay}"
ItemTemplate="{StaticResource Ufps}">
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement(TrvUfpsDictionary.SelectedItem)]"
/>
................
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
........
<Button Content="Test" Canvas.Left="475" Canvas.Top="568" Width="75"
cal:Message.Attach="[Event Click] = [Action AddElement(TrvUfpsDictionary.SelectedItem)]"/>
下面是简单的 ViewModel 代码:
public class UserSettingsViewModel : PropertyChangedBase
{
..........
public void AddElement(object selectedItem)
{
MessageBox.Show("Element added! "+selectedItem.?GetHashCode());
}
..........
}
现在我坚持了下来。当我选择了 treeview 的项目然后按下 "Test" 按钮时 - 它工作正常,它将所选项目传递到我的 VM 中的 "AddElement"。但是当我对 contextmenu 做同样的事情时 - 它总是传递 null。我错过了什么吗?
编辑
我已经针对所描述的问题制作了一个简单的应用程序。 https://github.com/whizzzkey/WpfApp1
您可能需要将上下文菜单进一步移动到 TreeView 中,移入项目模板并将上下文菜单添加到节点中的 Label/TextBlock。
例如,考虑下面的 Employee 树(因为我不知道你的数据结构而模拟),
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Positions}" >
<Label Content="{Binding DepartmentName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Employees}" >
<Label Content="{Binding PositionName}"
Tag="{Binding DataContext, ElementName=TestControl}" >
<Label.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]"/>
</ContextMenu>
</Label.ContextMenu>
</Label>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Label Content="{Binding EmployeeName}"
Tag="{Binding DataContext, ElementName=TestControl}">
<Label.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</Label.ContextMenu>
</Label>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
这里有几点需要注意。由于您的方法存在于 ViewModel 中,因此您必须确保 DataContext 指向您的 ViewModel 而不是绑定到节点的 Item Type。
为此,您需要使用cal:Action.TargetWithoutContext
。 Label 定义的下一行确保我们可以访问 View 的 DataContext。
Tag="{Binding DataContext, ElementName=TestControl}"
虽然以下行确保我们获得正确的绑定(到 ViewModel)。 TestControl
是您的 UserControl
的 x:Name
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
最后点击动作修改如下。
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]"
这将确保调用 ViewModel 的 Action 时传递了正确的参数。
更新
根据您的评论和代码,需要进行以下更改。
Window 定义 : 添加x:Name
<Window
x:Class="WpfApp1.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
Title="XmlData Tree Test"
x:Name="TestControl"
Width="250"
Height="350">
根分层模板
Associating Item source with Tag放在TextBlock上,Relative Source也有Self.
<HierarchicalDataTemplate DataType="root" ItemsSource="{Binding XPath=./*}" >
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0" Text="ROOT"
Tag="{Binding DataContext, ElementName=TestControl}">
<TextBlock.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
节点的分层模板
<HierarchicalDataTemplate
DataType="Node"
ItemsSource="{Binding XPath=./*}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0" Text="Node:" />
<TextBlock Margin="5,0,0,0"
Tag="{Binding DataContext, ElementName=TestControl}"
Text="{Binding XPath=@name}" >
<TextBlock.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
输出示例,
对于根
对于节点,
我的任务是在树视图中使用上下文菜单,并通过单击上下文菜单元素将所选树视图的项目传递给 ViewModel。
这是我的 xaml:
<Window.Resources>
<HierarchicalDataTemplate x:Key="Ufps"
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id}" />
<TextBlock Margin="5 0 0 0" Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
........
........
<TreeView x:Name="TrvUfpsDictionary" Height="222" Canvas.Left="25"
Canvas.Top="280" Width="545"
Background="AliceBlue"
ItemsSource="{Binding Path=Ufps, Mode=OneWay}"
ItemTemplate="{StaticResource Ufps}">
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement(TrvUfpsDictionary.SelectedItem)]"
/>
................
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
........
<Button Content="Test" Canvas.Left="475" Canvas.Top="568" Width="75"
cal:Message.Attach="[Event Click] = [Action AddElement(TrvUfpsDictionary.SelectedItem)]"/>
下面是简单的 ViewModel 代码:
public class UserSettingsViewModel : PropertyChangedBase
{
..........
public void AddElement(object selectedItem)
{
MessageBox.Show("Element added! "+selectedItem.?GetHashCode());
}
..........
}
现在我坚持了下来。当我选择了 treeview 的项目然后按下 "Test" 按钮时 - 它工作正常,它将所选项目传递到我的 VM 中的 "AddElement"。但是当我对 contextmenu 做同样的事情时 - 它总是传递 null。我错过了什么吗?
编辑 我已经针对所描述的问题制作了一个简单的应用程序。 https://github.com/whizzzkey/WpfApp1
您可能需要将上下文菜单进一步移动到 TreeView 中,移入项目模板并将上下文菜单添加到节点中的 Label/TextBlock。
例如,考虑下面的 Employee 树(因为我不知道你的数据结构而模拟),
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Positions}" >
<Label Content="{Binding DepartmentName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Employees}" >
<Label Content="{Binding PositionName}"
Tag="{Binding DataContext, ElementName=TestControl}" >
<Label.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]"/>
</ContextMenu>
</Label.ContextMenu>
</Label>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Label Content="{Binding EmployeeName}"
Tag="{Binding DataContext, ElementName=TestControl}">
<Label.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</Label.ContextMenu>
</Label>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
这里有几点需要注意。由于您的方法存在于 ViewModel 中,因此您必须确保 DataContext 指向您的 ViewModel 而不是绑定到节点的 Item Type。
为此,您需要使用cal:Action.TargetWithoutContext
。 Label 定义的下一行确保我们可以访问 View 的 DataContext。
Tag="{Binding DataContext, ElementName=TestControl}"
虽然以下行确保我们获得正确的绑定(到 ViewModel)。 TestControl
是您的 UserControl
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
最后点击动作修改如下。
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]"
这将确保调用 ViewModel 的 Action 时传递了正确的参数。
更新
根据您的评论和代码,需要进行以下更改。
Window 定义 : 添加x:Name
<Window
x:Class="WpfApp1.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org"
Title="XmlData Tree Test"
x:Name="TestControl"
Width="250"
Height="350">
根分层模板 Associating Item source with Tag放在TextBlock上,Relative Source也有Self.
<HierarchicalDataTemplate DataType="root" ItemsSource="{Binding XPath=./*}" >
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0" Text="ROOT"
Tag="{Binding DataContext, ElementName=TestControl}">
<TextBlock.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
节点的分层模板
<HierarchicalDataTemplate
DataType="Node"
ItemsSource="{Binding XPath=./*}">
<StackPanel Orientation="Horizontal">
<TextBlock Margin="0" Text="Node:" />
<TextBlock Margin="5,0,0,0"
Tag="{Binding DataContext, ElementName=TestControl}"
Text="{Binding XPath=@name}" >
<TextBlock.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Element"
cal:Message.Attach="[Event Click] = [Action AddElement($datacontext)]" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
输出示例, 对于根
对于节点,