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>
我有一个包含多个项目控件(树视图和其他)的应用程序,其中包含一个内部带有复选框的项目模板。此复选框选中状态绑定到项目视图模型的 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>