问题
I have a GridView with CheckBox as a column and TextBlock as another column. Here is the XAML code:
<ListView.View>
<GridView>
<GridView.ColumnHeaderContainerStyle>
<Style>
<Setter Property="UIElement.Visibility"
Value="Collapsed"/>
</Style>
</GridView.ColumnHeaderContainerStyle>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Tag="{Binding}"
IsChecked="{Binding Path=IsFormChecked, Mode=TwoWay}"
IsEnabled="{Binding Path=IsUnRestricted}"
IsThreeState="False"
UIElement.KeyUp="CheckBox_KeyUp" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Width="600"
Tag="{Binding}"
IsEnabled="{Binding Path=IsUnRestricted}"
Text="{Binding Path=FormName}"
MouseUp="TextBlock_MouseUp">
<TextBlock.ToolTip>
<TextBlock Text="{Binding Path=FormName}"/>
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
When I access this GridView with the keyboard complete row is selected (CheckBox as well as TextBlock). Now at this point if i press space key, nothing happens. If I want to access the CheckBox with keyboard, I have to press tab key once more so that focus is set on checkbox and the I can check/uncheck it using space bar. What I want to do is when the focus is on the row I want to check/uncheck checkbox with only one key press of space bar.
回答1:
If you have a binding on the currently selected item, you can handle the PreviewKeyUp event on your ListView:
<ListView PreviewKeyUp="OnGridKeyUp"
SelectedItem="{Binding MySelectedItem}"
SelectionMode="Single"
ItemsSource="{Binding ItemsList}">
...
</ListView>
and then handle this in code-behind:
private void OnGridKeyUp(object sender, KeyEventArgs e)
{
if(vm.mySelectedItem != null && e.Key == Key.Space)
{
vm.MySelectedItem.IsChecked = !vm.MySelectedItem.IsChecked;
e.Handled = true; //this is necessary because otherwise when the checkbox cell is selected, it will apply this keyup and also apply the default behavior for the checkbox
}
}
This obviously requires you to have a handle on your viewmodel from your code behind. This could be as easy as:
var vm = DataContext as MyViewModel;
this is not the most MVVM way, but hey...
回答2:
I made a more MVVM friendly way to do this:
Step 1: Create this behavior
public class ToggleSelectOnSpace : Behavior<DataGrid>
{
public static readonly DependencyProperty toggleSelectCommand =
DependencyProperty.Register("ToggleSelectCommand",
typeof(ICommand),
typeof(ToggleSelectOnSpace));
public ICommand ToggleSelectCommand
{
get { return this.GetValue(toggleSelectCommand) as ICommand; }
set { this.SetValue(toggleSelectCommand, value); }
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.PreviewKeyUp += PreviewKeyUp;
}
protected override void OnDetaching()
{
this.AssociatedObject.PreviewKeyUp -= PreviewKeyUp;
base.OnDetaching();
}
private void PreviewKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space)
{
if (ToggleSelectCommand != null)
{
ToggleSelectCommand.Execute(this.AssociatedObject.SelectedItems);
}
}
}
}
Step 2: Implement a command like this in your View Model (method logic for the command)
private void ToggleSelectParticipant(object selectedObjects)
{
var items = (System.Collections.IList)selectedObjects;
var collection = items.Cast<MyItemType>().ToList();
bool selection = !collection.All(x => x.IsSelected);
foreach (var item in collection)
item.IsSelected = selection;
}
Step 3: Bind the behavior to the grid, and bind the command to the behavior
<DataGrid>
<i:Interaction.Behaviors>
<shared:ToggleSelectOnSpace ToggleSelectCommand="{Binding Data.ToggleSelectParticipantCommand, Source={StaticResource BindingProxy}}" />
</i:Interaction.Behaviors>
...
</DataGrid>
(Info on the BindingProxy source)
来源:https://stackoverflow.com/questions/16939859/check-uncheck-checkbox-with-space-enter-in-gridview-in-listview-wpf