TreeView 的 HierarchicalDataTemplate 中的 KeyBinding

KeyBinding in HierarchicalDataTemplate of TreeView

我有一个TreeView。我想通过单击 F2 来启用 EditLeafCommand

型号:

public class Leaf
{
    public string LeafName { get; set; }
    public bool HasChildren { get; set; }        
}

Window 的视图模型:

public MainWindowViewModel{

  public ReadOnlyCollection<LeafViewModel> Leafs
  {
        get { return leafs; }
  }
}

TreeView 的 ViewModel:

public class LeafViewModel : TreeViewItemViewModel
{
    public ObservableCollection<TreeViewItemViewModel> Children
    {
        get { return _children; }
    }
    public string LeafName { get; set; }   
    public RelayCommand EditLeafCommand { get; set; }     

}

XAML:

<TreeView  ItemsSource="{Binding Leafs}">               
   <TreeView.InputBindings>
      <KeyBinding Key="F2" Command="{Binding SelectedItem.EditLeafCommand, 
                           diag:PresentationTraceSources.TraceLevel=High}"/>
   </TreeView.InputBindings>
   <TreeView.Resources>
      <HierarchicalDataTemplate DataType="{x:Type vm:LeafViewModel}" 
                                     ItemsSource="{Binding Children}">
         <StackPanel Orientation="Horizontal">               
            <TextBox Text="{Binding LeafName}" IsReadOnly="{Binding IsReadOnlyItem}" 
            Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}">
               <TextBox.ContextMenu>
                  <ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
                     <MenuItem Command="{Binding EditLeafCommand}" CommandParameter="{Binding ALeaf}" Header="Edit" />
                  </ContextMenu>
               </TextBox.ContextMenu>
            </TextBox>
         </StackPanel>
      </HierarchicalDataTemplate>
   </TreeView.Resources>
</TreeView>

输出window:

System.Windows.Data Warning: 56 : Created BindingExpression (hash=2683661) for Binding (hash=47044325)

System.Windows.Data Warning: 58 : Path: 'EditLeafCommand'

System.Windows.Data Warning: 60 : BindingExpression (hash=2683661): Default mode resolved to OneWay

System.Windows.Data Warning: 61 : BindingExpression (hash=2683661): Default update trigger resolved to PropertyChanged

System.Windows.Data Warning: 62 : BindingExpression (hash=2683661): Attach to System.Windows.Input.KeyBinding.Command (hash=29578451)

System.Windows.Data Warning: 64 : BindingExpression (hash=2683661): Use Framework mentor

System.Windows.Data Warning: 67 : BindingExpression (hash=2683661): Resolving source

System.Windows.Data Warning: 69 : BindingExpression (hash=2683661): Framework mentor not found

System.Windows.Data Warning: 65 : BindingExpression (hash=2683661): Resolve source deferred

System.Windows.Data Warning: 95 : BindingExpression (hash=2683661): Got InheritanceContextChanged event from KeyBinding (hash=29578451)

System.Windows.Data Warning: 67 : BindingExpression (hash=2683661): Resolving source

System.Windows.Data Warning: 70 : BindingExpression (hash=2683661): Found data context element: TreeView (hash=11903911) (OK)

System.Windows.Data Warning: 78 : BindingExpression (hash=2683661): Activate with root item MainWindowViewModel (hash=44115416)

System.Windows.Data Warning: 108 : BindingExpression (hash=2683661): At level 0 - for MainWindowViewModel.EditLeafCommand found accessor

System.Windows.Data Error: 40 : BindingExpression path error: 'EditLeafCommand' property not found on 'object' ''MainWindowViewModel' (HashCode=44115416)'. BindingExpression:Path=EditLeafCommand; DataItem='MainWindowViewModel' (HashCode=44115416); target element is 'KeyBinding' (HashCode=29578451); target property is 'Command' (type 'ICommand')

System.Windows.Data Warning: 80 : BindingExpression (hash=2683661): TransferValue - got raw value {DependencyProperty.UnsetValue}

System.Windows.Data Warning: 88 : BindingExpression (hash=2683661): TransferValue - using fallback/default value

System.Windows.Data Warning: 89 : BindingExpression (hash=2683661): TransferValue - using final value

我看到这个 post 和 it is it is the same question,然而,接受的答案没有任何代码(我试图通过 link,但是,提供的方法没有'帮帮我)

错误说:

System.Windows.Data Error: 40 :BindingExpression path error: 'EditLeafCommand' property not found on 'object' ''MainWindowViewModel'

但是我怎样才能指向 EditLeadViewModel

如何从LeafViewModel调用EditLeafCommand并发送参数?

您的 MainViewModel 没有 SelectedItem 属性。您需要将此 属性 添加到您的视图模型中,并确保在 属性 更改时触发 INotifyPropertyChanged.PropertyChanged 事件。

您还需要在树视图的选定项目更改时更新此 属性。有多种方法可以做到这一点。一种方法是使用 Nuget 包 System.Windows.Interactivity.WPF。您将必须添加命名空间声明:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

然后,在树视图 XAML 元素中添加以下内容(我只是展示要添加的内容 - 保持 TreeView 元素中 XAML 的其余部分完好无损) :

<TreeView Name="treeView" ItemsSource="{Binding Leafs}">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
      <i:InvokeCommandAction Command="{Binding SetSelectedItemCommand, PresentationTraceSources.TraceLevel=High}" CommandParameter="{Binding SelectedItem, ElementName=treeView}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>
</TreeView>

请注意,TreeView 元素的名称 (treeView) 用于 InvokeCommandAction 元素中的 CommandParameter 绑定。

此外,请注意您必须在 MainViewModel 上添加 SetSelectedItemCommand。此命令应设置我在开头段落中描述的 SelectedItem 属性。以下是一些使用通用 RelayCommand:

的代码片段
class MainWindowViewModel {

  TreeViewItemViewModel selectedItem;

  public MainWindowViewModel() {
    SetSelectedItemCommand = new RelayCommand<TreeViewItemViewModel>(SetSelectedItem);
  }

  public TreeViewItemViewModel SelectedItem {
    get { return selectedItem; }
    set {
      selectedItem = value;
      OnPropertyChanged();
    }
  }

  void SetSelectedItem(TreeViewItemViewModel viewModel) {
    SelectedItem = viewModel;
  }

}

这是使 SelectedItem.EditLeafCommand 的键绑定正常工作所需的基本内容。但是,您还有另一个问题。您的 HierarchicalDataTemplate 将树节点定义为 TextBox。当您单击 TextBox 时,不会冒泡到 TreeView,并且选择不会更改。我的建议是您使用每个树节点的非交互式表示(例如 TextBlock)。然后,当调用 EditLeafCommand 时,您在顶部放置一个 TextBox 以允许用户编辑节点。

Andy ONeill has solved this problem. 我对他的解决方案感到非常兴奋:)。赶紧把这个解决方法分享给大家:

绑定到 LeafViewModel 中的命令:

<TreeView  ItemsSource="{Binding Leafs}" Name="tv">
   <TreeView.Resources>
      <HierarchicalDataTemplate DataType="{x:Type local:LeafViewModel}" 
                                      ItemsSource="{Binding Children}">
         <StackPanel Orientation="Horizontal">
            <Label VerticalAlignment="Center" FontFamily="WingDings" Content="1"/>
               <TextBox Text="{Binding LeafName}" Tag="{Binding DataContext, 
                  RelativeSource={RelativeSource Self}}" Background="Transparent">
                  <TextBox.ContextMenu>
                     <ContextMenu DataContext="{Binding PlacementTarget.Tag, 
                                     RelativeSource={RelativeSource Self}}">
                        <MenuItem Command="{Binding EditLeafCommand}" 
                         CommandParameter="{Binding ALeaf}" Header="Edit" />
                     </ContextMenu>
                  </TextBox.ContextMenu>
               </TextBox>
            </StackPanel>
         </HierarchicalDataTemplate>
      </TreeView.Resources>
    <TreeView.InputBindings>
    <KeyBinding Key="F2" Command="{Binding SelectedItem.EditLeafCommand, ElementName=tv}"/>
    </TreeView.InputBindings>
</TreeView>