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>

输出示例, 对于根

对于节点,