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>
我有一个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>