Ви движемся через DataGrid
Я использую 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 не добавляет в список выбранных элементов. Кажется, что мультиселектор не хочет включаться, пока вы не используете Shift и Up / Down или 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;
}
1 ответ
Если я правильно понимаю проблему - у вас есть фокус и выбор в каждой строке. Вы хотите переместить фокус с помощью клавиш k/j и переключить выбор с помощью клавиши x.
Мне нравится использовать поведение в этих ситуациях - для этого требуется ссылка на System.Windows.Interactivity.dll из blen SDK, но также для более чистого и модульного кода.
[edit: это быстрый 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. Вы можете испечь логику для первоначального выбора в поведении (или в новом поведении).