Сетка данных WPF и клавиша табуляции - PullRequest
11 голосов
/ 14 апреля 2011

Еще один вопрос о связывании ключей для таблицы данных

У меня есть таблица данных.В нем выбран режим выбора FullRow и KeyboardNavigation.TabNavigation = "Once", который, как я надеялся, получит желаемый результат, но это не так.

Когда клавиша табуляции нажата, когда сетка данных находится в фокусе, она будет перемещаться по каждому столбцу в сетке один за другим.Поэтому, если я вкладываю вкладку в сетку, которая имеет 4 столбца, мне придется нажимать вкладку 4 раза, чтобы перейти к следующему индексу вкладки.

Я хочу, чтобы клавиша табуляции вставляла сразу из сетки данных при первом нажатии и фокусировалась на следующем индексе табуляции ... если это имеет смысл.

Я попытался переопределить клавишу табуляции в обработчике события keydown следующим образом.

class BetterDataGrid : DataGrid
{
  ..............
  protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
  {
    ..............
    if (e.Key == Key.Tab)
    {
        Console.WriteLine("TAB");
        MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
    }
    .........
  }

Он записывает «TAB» в консоль, но вкладка по-прежнему сохраняет поведение по умолчанию.Не уверен, что это правильный путь перехода к следующему tabindex, но тогда это должно заставить клавишу tab ничего не делать, кроме записи в консоль или вызывать исключение.
Заставляет меня думать, что невозможно переопределить поведение клавиши tab.

Надеемся на полезный вклад.
Как всегда, заранее спасибо.

Ответы [ 2 ]

9 голосов
/ 14 апреля 2011

Я хотел, чтобы это было для моего программного обеспечения для бизнеса, и единственный способ, который я нашел, чтобы решить это, это с помощью кода, используя события PreviewKeyDown, GotKeyboardFocus и LostKeyboardFocus сетки данных.Я поместил эти обработчики событий в декоратор WPF, чтобы не повторять его для каждой отдельной DataGrid.Вероятно, можно было бы создать подкласс DataGrid, но я этого не пробовал.

Код для обработчиков следующий (DataGrid для этого примера кода: x: Name = "grid"):

        private IInputElement lastDataGridFocus = null;
    private int selectedcolumnindex = 0;

    void grid_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (grid.Items.Count > 0 && (e.NewFocus is DataGrid || (e.NewFocus is DataGridCell && !(e.OldFocus is DataGridCell))))
        {
            DataGridCell cell = null;

            if (lastDataGridFocus != null)
            {
                FocusManager.SetFocusedElement(grid, lastDataGridFocus);
                lastDataGridFocus = null;
                e.Handled = true;
                return;
            }

            if (grid.SelectedCells.Count == 0)
            {
                DataGridRow rowContainer = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(0);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
                    cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex((selectedcolumnindex < 0) ? 0 : selectedcolumnindex);
                }
            }
            else
            {
                DataGridCellInfo selectedDataGridCellInfo = (grid.SelectedCells[0] as DataGridCellInfo?).Value;
                DataGridRow rowContainer = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(selectedDataGridCellInfo.Item);
                if (rowContainer != null)
                {
                    DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
                    cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex((selectedcolumnindex < 0) ? 0 : selectedcolumnindex);
                }
            }
            if (null != cell)
            {
                FocusManager.SetFocusedElement(grid, cell as IInputElement);
                e.Handled = true;
            }
        }
    }

    void grid_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (!(e.NewFocus is DataGridCell))
        {
            if (grid.CurrentCell != null)
            {
                selectedcolumnindex = grid.Columns.IndexOf(grid.CurrentCell.Column);
            }
        }
    }

    void grid_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (Keyboard.Modifiers == ModifierKeys.Shift && e.Key == Key.Tab)
        {
            lastDataGridFocus = Keyboard.FocusedElement;
            grid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
            e.Handled = true;
        }
        else if (Keyboard.Modifiers == ModifierKeys.None && e.Key == Key.Tab)
        {
            lastDataGridFocus = Keyboard.FocusedElement;
            grid.MoveFocus(new TraversalRequest(FocusNavigationDirection.Last));
            (Keyboard.FocusedElement as FrameworkElement).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            e.Handled = true;
        }
    }

С помощью этого кода вы можете перемещаться по сетке с помощью клавиш курсора, а клавиша табуляции и клавиша Shift-Tab выводят вас из сетки данных.Если вы выйдете из сетки и вернетесь к ней, вы также попадете в ту же ячейку, что и ушли.Это то, что я и мои пользователи хотим, и это IMHO, что элемент управления DataGrid должен обеспечивать как поведение по умолчанию.

0 голосов
/ 14 апреля 2011

То, что вы пытаетесь достичь, не является правильным поведением, все ожидают, что Excel будет похож на навигацию при нажатии клавиши Tab, когда сосредоточена DataGrid. Лучше предотвратить остановки табуляции в DataGrid, установив IsTabStop="False" в DataGrid, если вы не хотите, чтобы пользователь перемещался по DataGrid.

...