1
votes

I have a DataGrid with few editable cells. Users can tab through each cells to edit the content. Now I want to implement the right arrow key working just like tab. So when a user finishes editing one cell and they press right arrow key, the focus moves to the next editable cell and starts editing.

For example, I have follow screen:

When user press right arrow key, I want my datagrid to be like this:

4

4 Answers

1
votes

The DataGrid actually auto-handles right, left, up, down arrow keys. That being said, you can move the cell focus around using any of those keys and then start typing to get into the edit mode (iff the cell is editable). You don't have to listen to key press down events. Note that if you hit "Enter", then you will move to the next row.

EDIT:

Of course, by default the arrow keys won't put a cell into edit mode. Instead, you have to type in stuff or use the mouse pointer. But, you can do the following:

    private void myDataGrid_CurrentCellChanged(object sender, EventArgs e)
    {
        myDataGrid.BeginEdit();
    }

This will force the cell on focus to enter the edit mode. I tried using key event handlers, but it seems the DataGrid won't let the user listen to the arrow keys and Enter (although you could if you use WIN32 API). Now, whenever you use any of the arrow keys, the newly selected cell will be in edit mode. Try hitting Esc to escape this mode.

0
votes

This is the code I use for navigation using the arrow keys

Its placed inside the Datagrid_KeyUp event

    DataGridCell DGcell = new DataGridCell();
    DGcell = GetCell(index, _Header);
    if (DGcell != null)
    {
         CurrentCellContentType = DGcell.Content.GetType().Name.ToString();
    }
    DataGridCell ProdCodeCell = GetCell(index, 0);
    DataGridCell DescCell = GetCell(index, 1);
    DataGridCell CostPriceCell = GetCell(index, 4);
    DataGridCell VatRateCell = GetCell(index, 9);

    DataGridCellInfo PCell = new DataGridCellInfo(ProdCodeCell);
    DataGridCellInfo DCell = new DataGridCellInfo(DescCell);
    DataGridCellInfo PriceCell = new DataGridCellInfo(CostPriceCell);
    DataGridCellInfo VatCell = new DataGridCellInfo(VatRateCell);

    string ProdCellContentType = PCell.Column.GetCellContent(PCell.Item).GetType().Name.ToString();
    string DescCellContentType = DCell.Column.GetCellContent(DCell.Item).GetType().Name.ToString();
    string PriceCellContentType = PriceCell.Column.GetCellContent(PriceCell.Item).GetType().Name.ToString();
    string VatCellContentType = VatCell.Column.GetCellContent(VatCell.Item).GetType().Name.ToString();

    switch (e.Key)
    {
    case Key.Left:
        if (CurrentCellContentType == "TextBlock") e.Handled = false;
        else if (CurrentCellContentType == "TextBox")
        {
            DataGridCellInfo cellLeft = new DataGridCellInfo(GetCell(index, _Header - 1));
            DgInvoiceLines.CurrentCell = cellLeft;
        }
        break;
    case Key.Right:
        if (CurrentCellContentType == "TextBlock") else e.Handled = false;

        else if (CurrentCellContentType == "TextBox")
        {
            DataGridCellInfo cellRight = new DataGridCellInfo(GetCell(index, _Header + 1));
            DgInvoiceLines.CurrentCell = cellRight;
        }
        break;
    case Key.Up:
        if (index != 0)
        {
            if (CurrentCellContentType == "TextBlock") e.Handled = false;
            else if (CurrentCellContentType == "TextBox")
            {
                DataGridCellInfo cellUp = new DataGridCellInfo(GetCell(index - 1, _Header));
                DgInvoiceLines.CurrentCell = cellUp;
                DgInvoiceLines.SelectedItem = DgInvoiceLines.Items[index - 1];
            }
        }
        break;

    case Key.Down:
        if (CurrentCellContentType == "TextBlock") e.Handled = false;
        else if (CurrentCellContentType == "TextBox")
        {
            DataGridCellInfo cellDown = new DataGridCellInfo(GetCell(index + 1, _Header));
            DgInvoiceLines.CurrentCell = cellDown;
            DgInvoiceLines.SelectedItem = DgInvoiceLines.Items[index + 1];
        }
        break;

I use a switch statement to assign a number to each column header

HTH.

0
votes

this is my solution, which works.

In constructor:

dataGridSubmissionData.KeyUp += DataGridSubmissionDataOnKeyUp;
            dataGridSubmissionData.BeginningEdit += DataGridSubmissionDataOnBeginningEdit;
            dataGridSubmissionData.CellEditEnding += DataGridSubmissionDataOnCellEditEnding;
            dataGridSubmissionData.CurrentCellChanged += DataGridSubmissionDataOnCurrentCellChanged;

In body class:

private bool isCellInEditionMode = false;

 private void DataGridSubmissionDataOnCurrentCellChanged(object sender, EventArgs eventArgs)
        {
            dataGridSubmissionData.BeginEdit();
        }

        private void DataGridSubmissionDataOnCellEditEnding(object sender, DataGridCellEditEndingEventArgs dataGridCellEditEndingEventArgs)
        {
            isCellInEditionMode = false;
        }

        private void DataGridSubmissionDataOnBeginningEdit(object sender, DataGridBeginningEditEventArgs dataGridBeginningEditEventArgs)
        {
            isCellInEditionMode = true;
        }

private void DataGridSubmissionDataOnKeyUp(object sender, KeyEventArgs keyEventArgs)
        {
            if (keyEventArgs.Key == Key.Up || keyEventArgs.Key == Key.Down || keyEventArgs.Key == Key.Left || keyEventArgs.Key == Key.Right)
            {
                if (!isCellInEditionMode)
                    return;

                dataGridSubmissionData.CommitEdit();

                var key = keyEventArgs.Key; // Key to send
                var target = dataGridSubmissionData; // Target element
                var routedEvent = Keyboard.KeyDownEvent; // Event to send

                target.RaiseEvent(
                    new KeyEventArgs(
                        Keyboard.PrimaryDevice,
                        PresentationSource.FromVisual(target),
                        0,
                        key) {RoutedEvent = routedEvent}
                    );
            }
        }

I hope that my answer will help someone.

0
votes

If your case is WPF hosted window, it called Modeless WPF.

And the solution might be this:

Window window = new Window();
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(window);
window.Show();

I've seen the solution here