2013-09-09 4 views
0

Я использую DataGrid, чтобы отобразить кучу данных. У меня есть SelectionMode="Extended" и SelectionUnit="FullRow".Vi перемещение через DataGrid

То, что я хотел бы быть в состоянии сделать это нажать 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 не добавляет к списку выбранных элементов. Это кажется несколько выбора не хочет пинать, пока вы не будете использовать сдвиг и вверх/вниз или смещение мыши

редактировать

Ok, так что я понял, как перемещаться с помощью клавиши 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

'Вот что я пробовал до сих пор' - Ницца. Какие у вас проблемы с вашим текущим подходом? –

+0

Да, поэтому текущая строка не перемещается вверх или вниз. Я также пробовал FocusNavigationDirection.Previous и Next, и они не работают. Если я иду по индексу, они перемещаются, но нажатие X не добавляет к списку выбранных элементов. Кажется, multi select не хочет пинать до тех пор, пока вы не нажмете shift и вверх/вниз или сдвиньте мышью. –

ответ

1

Если я правильно понял проблему - у вас есть фокус и выбор в строке. Вы хотите перемещать фокус с помощью клавиш k/j и переключаться с помощью клавиши x.

Мне нравится использовать поведение в этих ситуациях - для этого требуется ссылка на System.Windows.Interactivity.dll из blen SDK, но это также делает более чистый и модульный код.

[Редактировать: Это быстрый 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. Вы можете испечь логику для первоначального выбора в поведении (или в новом поведении).

+0

Я сделаю это через несколько часов, скрестив пальцы, это похоже на действительно приятное решение. –

+0

Ну, я думаю, ты выиграл здесь. Прекрасно работает. После игры с ним, хотя я понял, что выбор материала, вероятно, не подходит для того, что я пытаюсь сделать (я имею в виду, что это работает, но для моего приложения идея мультиселекции подобна этому не была хорошей). Движение материала здорово. –

+0

Кроме того, я думаю, вы сможете совершить тот же подвиг, не имея при себе поведения на борту, когда я думаю об этом. Тем не менее, это приятное решение. –