简体   繁体   中英

TreeViewItems and Keybinding

I'm trying to set keybinding on my TreeView items using technique described here (the first answer). So I have a TreeView in XAML, an ICommand property defined in TreeView item's ViewModel, and a helper class registering attached property to support keybinding in TreeViewItem's style. But every time the command is only invoked on the first item of my TreeView no matter which item was actually selected. Why is that and how can I fix it? Or may be there is some better way to set keybinding on TreeViewItems without breaking MVVM pattern?

XAML

<TreeView x:Name="tr" ItemsSource="{Binding Root}">
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="local:AttachedTVIBinding.InputBindings">
                    <Setter.Value>
                        <InputBindingCollection>
                            <KeyBinding Key="A" Command="{Binding SomeCommand}"/>
                            <MouseBinding Gesture="LeftDoubleClick" Command="{Binding SomeCommand}"/>
                        </InputBindingCollection>
                    </Setter.Value>
                </Setter>
            </Style>
        </TreeView.ItemContainerStyle>
</TreeView>

TreeViewItem's ViewModel

public class ConfigurationNodeViewModel : INotifyPropertyChanged
{
        private DelegateCommand _someCommand;

        public DelegateCommand SomeCommand
        {
            get { return _editDesignCommand; }
        }
}

Helper class (exactly like in the link provided)

public class AttachedTVIBinding : Freezable
    {
        public static readonly DependencyProperty InputBindingsProperty =
            DependencyProperty.RegisterAttached("InputBindings", typeof(InputBindingCollection), typeof(AttachedTVIBinding),
            new FrameworkPropertyMetadata(new InputBindingCollection(),
            (sender, e) =>
            {
                var element = sender as UIElement;
                if (element == null) return;
                element.InputBindings.Clear();
                element.InputBindings.AddRange((InputBindingCollection)e.NewValue);
            }));

        public static InputBindingCollection GetInputBindings(UIElement element)
        {
            return (InputBindingCollection)element.GetValue(InputBindingsProperty);
        }

        public static void SetInputBindings(UIElement element, InputBindingCollection inputBindings)
        {
            element.SetValue(InputBindingsProperty, inputBindings);
        }

        protected override Freezable CreateInstanceCore()
        {

            return new AttachedTVIBinding();
        }

    }

Here is a 3 years late answer but might be useful for someone.

The solution is to use a style which applies a non-shared resource containing your KeyBinding and MouseBinding elements by setting x:Shared="False". This allows to create more than 1 instance of InputBindingCollection as WPF by default creates only a single instance of a style.

<InputBindingCollection x:Key="myBindings" x:Shared="False">
    <KeyBinding Key="A" Command="{Binding SomeCommand}"/>
    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding SomeCommand}"/>
</InputBindingCollection>

<Style TargetType="{x:Type TreeViewItem}">
    <Setter Property="local:AttachedTVIBinding.InputBindings" Value="{DynamicResource myBindings}"/>
</Style>

Please note that x:Shared can only be used within a compiled ResourceDictionary. You can also use the same ResourceDictionary in which you have defined a style for TreeViewItem but InputBindingCollection needs to be placed above this style.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM