TreeViewItems 和键绑定

发布于 2024-12-05 11:34:21 字数 2614 浏览 1 评论 0原文

我正在尝试使用此处描述的技术在我的 TreeView 项目上设置键绑定(第一个答案)。因此,我有一个 XAML 中的 TreeView、一个在 TreeView 项的 ViewModel 中定义的 ICommand 属性,以及一个注册附加属性以支持 TreeViewItem 样式中的键绑定的帮助程序类。但每次只在 TreeView 的第一个项目上调用该命令,无论实际选择了哪个项目。这是为什么?我该如何解决它?或者可能有一些更好的方法可以在 TreeViewItems 上设置键绑定而不破坏 MVVM 模式?

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

public class ConfigurationNodeViewModel : INotifyPropertyChanged
{
        private DelegateCommand _someCommand;

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

Helper 类(与提供的链接中完全相同)

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();
        }

    }

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();
        }

    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

眼眸里的快感 2024-12-12 11:34:21

这是一个迟了三年的答案,但可能对某人有用。

解决方案是使用一种样式,通过设置 x:Shared="False" 来应用包含 KeyBinding 和 MouseBinding 元素的非共享资源。这允许创建 1 个以上的 InputBindingCollection 实例,因为 WPF 默认情况下仅创建样式的单个实例。

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

请注意,x:Shared 只能在已编译的 ResourceDictionary 中使用。
您还可以使用为 TreeViewItem 定义样式的相同 ResourceDictionary,但需要将 InputBindingCollection 放置在该样式之上。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文