我使用一个DataGrid来显示一堆数据。我有SelectionMode="Extended"和SelectionUnit="FullRow"。
我想要做的是按J将焦点向下移动到网格中,按K在网格中向上移动,然后按x将焦点行添加/删除到SelectedItems列表中(基本上就像gmail中的键盘快捷键)。
我对wpf很在行,但我还没有做到这一点。我不确定行焦点是否与所选的项目分开,但我想到底是什么原因,也许这里有人做了类似的事情。
以下是我迄今所尝试的
case Key.X:
{
resultsGrid.SelectedItems.Add(resultsGrid.SelectedItem);
e.Handled = true;
break;
}
case Key.J:
{
//down
var currow = (DataGridRow) resultsGrid.ItemContainerGenerator.ContainerFromItem(resultsGrid.SelectedItem);
currow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
//if (resultsGrid.SelectedIndex + 1 >= resultsGrid.Items.Count)
// resultsGrid.SelectedIndex = 0;
//else
// resultsGrid.SelectedIndex++;
break;
}
case Key.K:
{
//up
var currow =
(DataGridRow) resultsGrid.ItemContainerGenerator.ContainerFromItem(resultsGrid.SelectedItem);
currow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up));
//if (resultsGrid.SelectedIndex - 1 <= 0)
// resultsGrid.SelectedIndex = resultsGrid.Items.Count - 1;
//else
// resultsGrid.SelectedIndex--;
break;
}当前行不向上或向下移动。我也尝试过FocusNavigationDirection.Previous和Next,它们也不会转移焦点。如果我按索引,它会移动,但按X键不会添加到所选项目的列表中。似乎多个select不想启动,直到您使用shift和上/下鼠标单击。
编辑
好的,我已经知道了如何使用j和k键导航,但是选择仍然不起作用。如果我向上或向下移动,它会清除所选内容,同时按x也不会做任何事情,至少在视觉上是这样的。
case Key.X:
resultsGrid.SelectedItems.Add(resultsGrid.SelectedItem);
e.Handled = true;
break;
case Key.J:
{
//down
InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Down)
{
RoutedEvent = Keyboard.KeyDownEvent
});
resultsGrid.ScrollIntoView(resultsGrid.SelectedItem);
e.Handled = true;
break;
}
case Key.K:
{
//up
InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Up)
{
RoutedEvent = Keyboard.KeyDownEvent
});
resultsGrid.ScrollIntoView(resultsGrid.SelectedItem);
e.Handled = true;
break;
}发布于 2013-09-09 21:30:56
如果我正确理解了这个问题,那么每一行都有一个焦点和选择。您希望通过k/j键移动焦点,并通过x键切换选择。
我喜欢在这些情况下使用行为-它需要参考来自blen的System.Windows.Interactivity.dll,但它也提供了一个更干净和模块化的代码。
编辑:--这是我所做的快速POC。它可能需要更多的空引用保护和边缘/边缘情况的处理。
其行为是:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace GridNavigationTest
{
public class GridNavigationBehavior : Behavior<DataGrid>
{
#region Overrides of Behavior
/// <summary>
/// Called after the behavior is attached to an AssociatedObject.
/// </summary>
/// <remarks>
/// Override this to hook up functionality to the AssociatedObject.
/// </remarks>
protected override void OnAttached()
{
AssociatedObject.PreviewKeyDown += AssociatedObject_KeyDown;
}
/// <summary>
/// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
/// </summary>
/// <remarks>
/// Override this to unhook functionality from the AssociatedObject.
/// </remarks>
protected override void OnDetaching()
{
AssociatedObject.KeyDown -= AssociatedObject_KeyDown;
}
#endregion
#region Event handlers
void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.J:
NavigateGridFocus(FocusNavigationDirection.Up);
break;
case Key.K:
NavigateGridFocus(FocusNavigationDirection.Down);
break;
case Key.X:
ToggleRowSelection();
break;
}
}
#endregion
#region Methods
private void ToggleRowSelection()
{
var currentlyFocusedRow = FindCurrentlyFocusedRow();
if (currentlyFocusedRow == null)
{
return;
}
var generator = AssociatedObject.ItemContainerGenerator;
var rowItem = generator.ItemFromContainer(currentlyFocusedRow);
if (AssociatedObject.SelectionMode == DataGridSelectionMode.Extended)
{
if (AssociatedObject.SelectedItems.Contains(rowItem))
{
AssociatedObject.SelectedItems.Remove(rowItem);
}
else
{
AssociatedObject.SelectedItems.Add(rowItem);
}
}
else
{
AssociatedObject.SelectedItem = AssociatedObject.SelectedItem == rowItem ? null : rowItem;
}
}
private void NavigateGridFocus(FocusNavigationDirection direction)
{
var currentlyFocusedRow = FindCurrentlyFocusedRow();
if (currentlyFocusedRow == null)
{
return;
}
var traversalRequest = new TraversalRequest(direction);
var currentlyFocusedElement = Keyboard.FocusedElement as UIElement;
if (currentlyFocusedElement != null) currentlyFocusedElement.MoveFocus(traversalRequest);
}
private DataGridRow FindCurrentlyFocusedRow()
{
var generator = AssociatedObject.ItemContainerGenerator;
if (generator.Status != GeneratorStatus.ContainersGenerated)
{
return null;
}
for (var index = 0; index < generator.Items.Count - 1; index++)
{
var row = generator.ContainerFromIndex(index) as DataGridRow;
if (row != null && row.IsKeyboardFocusWithin)
{
return row;
}
}
return null;
}
#endregion
}
} 其用途是:
<Window x:Class="GridNavigationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gridNavigationTest="clr-namespace:GridNavigationTest"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<DataGrid ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type gridNavigationTest:MainWindow}}, Path=People}">
<i:Interaction.Behaviors>
<gridNavigationTest:GridNavigationBehavior/>
</i:Interaction.Behaviors>
<!--This is here just for testing of focus movement-->
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin"
Value="True">
<Setter Property="Background"
Value="HotPink" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
</Grid>
</Window>这要求其中一个行将IsKeyboardFocuedWithin设置为true。您可以将初始选择的逻辑分解为行为(或者,在新的行为中)。
https://stackoverflow.com/questions/18703475
复制相似问题