check/uncheck 列表项中复选框的 WPF 行为

WPF behaviour to check/uncheck a checkbox in a list item

我有一个包含多个项目控件(树视图和其他)的应用程序,其中包含一个内部带有复选框的项目模板。此复选框选中状态绑定到项目视图模型的 IsChecked 属性。这在单击复选框时工作正常,但不可能用键盘 check/uncheck 它们(我相信这是由于复选框本身永远不会获得焦点的事实)。

我喜欢 DLeh 在这里提出的解决方案: 但我想要一个改进:而不是在基本视图模型(包含项目列表的虚拟机)上调用命令的行为,我希望该行为直接作用于项目的 IsChecked 属性。 我的问题是我不知道如何修改行为或如何设置绑定,以便行为可以访问项目的 IsChecked 属性。 所以,而不是以下内容:

<DataGrid>
    <i:Interaction.Behaviors>
        <shared:ToggleSelectOnSpace ToggleSelectCommand="{Binding Data.ToggleSelectParticipantCommand, Source={StaticResource BindingProxy}}" />
    </i:Interaction.Behaviors>
...
</DataGrid>

我会有这样的东西:

<DataGrid>
    <i:Interaction.Behaviors>
        <shared:ToggleSelectOnSpace ItemsIsSelectedProperty="{Binding IsChecked}" />
    </i:Interaction.Behaviors>
...
</DataGrid>

更新 我应该补充一点,我当前的实现使用 itemscontrol 中的 PreviewKeyUp 事件和下面的实现代码。这种方法的问题是我在许多代码隐藏文件中都有这段代码,所以有很多重复。我的目标是用一种行为来代替它。

private void TreeView_OnPreviewKeyUp(object sender, KeyEventArgs e)
{
   if (e.Key == Key.Space)
   {
        var tree = (TreeView) sender;
        var item = tree.SelectedItem as IsSelectedViewModelBase;
        if (item != null)
        {
            item.IsSelected = !item.IsSelected;
            e.Handled = true;
        }
   }
}

更新 2 这是项目模板,当您在选择项目的情况下按 space 栏时不会选中复选框。

<DataTemplate DataType="{x:Type viewModels:ItemViewModel}" >
    <StackPanel Orientation="Horizontal" >
      <CheckBox Focusable="False" IsChecked="{Binding IsSelected}" VerticalAlignment="Center" />
      <StackPanel Margin="2">
           <TextBlock Text="{Binding Username}" FontWeight="Bold" />
            <TextBlock Text="{Binding FullName}" />
      </StackPanel>
   </StackPanel>
 </DataTemplate>

不是问题的答案本身,但下面将说明列表项中的复选框可以接收键盘焦点。

我使用默认 Visual Studio 模板创建了一个新的 WPF 项目。这将创建一个名为 "MainWindow" 的 window。这是 XAML 的内容和 window.

的隐藏代码

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Thingies = new List<Thingy>
            {
                new Thingy { Name = "abc", IsChecked = false },
                new Thingy { Name = "def", IsChecked = true },
                new Thingy { Name = "ghi", IsChecked = false },
                new Thingy { Name = "jkl", IsChecked = true },
                new Thingy { Name = "mno", IsChecked = false },
            }.ToArray();

            DataContext = this;
        }

        public Thingy[] Thingies { get; private set; }

        public class Thingy : INotifyPropertyChanged
        {
            public string Name { get; set; }

            public bool IsChecked
            {
                get
                {
                    return _isChecked;
                }
                set
                {
                    if (_isChecked != value)
                    {
                        _isChecked = value;
                        if (PropertyChanged != null)
                        {
                            PropertyChanged(this,
                                new PropertyChangedEventArgs("IsChecked"));
                        }
                        Console.WriteLine(Name + " = " + _isChecked);
                    }
                }
            }
            bool _isChecked;

            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <ListBox ItemsSource="{Binding Thingies}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <UniformGrid Rows="1" Width="400">
                    <TextBlock Text="{Binding Name}" />
                    <CheckBox IsChecked="{Binding IsChecked}" />
                </UniformGrid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>