问题
I have an application with several item controls (treeviews and others) which contain an item template with a checkbox inside. This checkbox checked state is bound to an IsChecked property of the item view model. This works correctly when clicking on the checkbox, but it's impossible to check/uncheck them with the keyboard (I believe this is due to the fact that the checkbox itself never gets the focus).
I like the solution proposed by DLeh in here: https://stackoverflow.com/a/24327765/352826 but I would like an improvement: Instead of having the behaviour calling a command on the base view model (the vm which contains the list of items), I would like the behaviour to directly act on the IsChecked property of the item. My problem is that I don't know how to modify the behaviour or how to set up the binding on it, so that the behaviour can have access to the item's IsChecked property. So, instead of the following:
<DataGrid>
<i:Interaction.Behaviors>
<shared:ToggleSelectOnSpace ToggleSelectCommand="{Binding Data.ToggleSelectParticipantCommand, Source={StaticResource BindingProxy}}" />
</i:Interaction.Behaviors>
...
</DataGrid>
I would have something like this:
<DataGrid>
<i:Interaction.Behaviors>
<shared:ToggleSelectOnSpace ItemsIsSelectedProperty="{Binding IsChecked}" />
</i:Interaction.Behaviors>
...
</DataGrid>
Update I should add that my current implementation uses the PreviewKeyUp event in the itemscontrol and the following code behind implementation. The problem with this approach is that I have this code in many code behind files, so there is a lot of duplication. My goal is to replace this by a behaviour.
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;
}
}
}
Update 2 This is the item template and the checkbox is not checked when you press the space bar with the item selected.
<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>
回答1:
Not an answer to the asked question per se, but the following will illustrate that it is possible for a check box within a list item to receive keyboard focus.
I created a new WPF project using the default Visual Studio template. This creates a single window called "MainWindow". Here's the contents of the XAML and code-behind of that 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>
来源:https://stackoverflow.com/questions/28457497/wpf-behaviour-to-check-uncheck-a-checkbox-in-a-list-item