KeyBinding in TreeView hierarchical data table

I have a TreeView . I would like to enable EditLeafCommand by pressing F2 .

Model:

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

ViewModel windows:

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

ViewModel TreeView:

 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> 

and Output Window :

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

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

System.Windows.Data Warning: 60: BindingExpression (hash = 2683661): The default mode is enabled for OneWay

System.Windows.Data Warning: 61: BindingExpression (hash = 2683661): default update trigger enabled for 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): Source Resolution

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

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

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

System.Windows.Data Warning: 67: BindingExpression (hash = 2683661): Source Resolution

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

System.Windows.Data Warning: 78: BindingExpression (hash = 2683661): Activate using the root element MainWindowViewModel (hash = 44115416)

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

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

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

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

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

I see this post and this is the same question , however the accepted answer has no code (I tried to go through the link, however, the proposed approach did not help me)

The error says:

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

But how can I go to EditLeadViewModel ?

How can I call EditLeafCommand from LeafViewModel and send the parameter?

+1
c # wpf mvvm xaml treeview
source share
2 answers

Andy Onell solved this problem. I am very happy with his decision :). I am in a hurry to share this solution with you:

To bind to a command in 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> 
0
source share

Your MainViewModel does not have a SelectedItem property. You need to add this property to your view model and make sure that the INotifyPropertyChanged.PropertyChanged event INotifyPropertyChanged.PropertyChanged fired when this property changes.

You also need to update this property when the selected tree structure item changes. There are various ways to do this. One way is to use the Nuget System.Windows.Interactivity.WPF package. You will need to add a namespace declaration:

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

Then, inside the XAML tree element, add the following (I only show what to add - leave the rest of your XAML inside the TreeView element intact):

 <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> 

Notice that the TreeView element has a name ( TreeView ) that is used in the CommandParameter binding in the InvokeCommandAction element.

Also note that you need to add SetSelectedItemCommand to MainViewModel . This command should set the SelectedItem property, which I described in my original paragraph. Here are the code snippets using the generic 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; } } 

This is the basic material needed for your key binding to SelectedItem.EditLeafCommand work. However, you have one more problem. Your HierarchicalDataTemplate defines the node tree as a TextBox . When you click on the TextBox button, no buttons will be pressed on the TreeView , and the selection will not be changed. My suggestion is that you use a non-interactive representation of each node tree (e.g. a TextBlock ). Then, when EditLeafCommand is EditLeafCommand , you put a TextBox on top, allowing the user to edit the node.

+1
source share

All Articles