none
Bypass read only cells in DatagridView when pressing TAB key RRS feed

  • Question

  • Can anyone show me some code of how I could bypass read only cells in DatagridView when pressing TAB key?
    Tuesday, April 14, 2009 1:44 PM

Answers

  • Hi Cornel,

    To stop navigating to a readonly cell in a DataGridView via Tab, we could derive a new class from DataGridView and override the ProcessDialogKey and ProcessDataGridViewKey methods in the subclass.

     

    When the current cell in a DataGridView is in edit mode, and the user press a key, the override ProcessDialogKey method is called. When the current cell is not in edit mode, and the user press a key, the override ProcessDataGridViewKey method is called. So these two methods compensate each other.

     

    In the overrid ProcessDialogKey and ProcessDataGridViewKey methods, seek the next editable cell and if find then set it as the current cell.

     

    In addition, to prevent the user from selecting the readonly cells via mouse, we could override the WndProc method in the derived DataGridView class to catch the WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages. If the cell to be selected is readonly, discard the Windows message, so that the cell won't be selected; otherwise let the message go.

     

    The following is a sample:

     

    class MyDataGridView:DataGridView

        {

            protected override bool ProcessDialogKey(Keys keyData)

            {

                Keys key = (keyData & Keys.KeyCode);

     

                if (key == Keys.Enter ||  key == Keys.Right|| key == Keys.Down)

                {

                    SendKeys.Send("{Tab}");

                    return true;

                }

                else if (key == Keys.Left || key == Keys.Up )

                {

                    return true;

                }

                if (key == Keys.Tab)

                {

                    int col = this.CurrentCell.ColumnIndex + 1;

                    for (; col < this.Columns.Count; col++)

                    {

                        if (!this.Columns[col].ReadOnly)

                        { break; }

                    }

                    if (col < this.Columns.Count)

                    {

                        this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];

                    }

                    else

                    {

                        if (this.CurrentCell.RowIndex != this.Rows.Count - 1)

                        {

                            for (col = 0; col <= this.CurrentCell.ColumnIndex;col++)

                            {

                                if (!this.Columns[col].ReadOnly)

                                {

                                    break;

                                }

                            }

                            if (col <= this.CurrentCell.ColumnIndex)

                            {

                                this.CurrentCell =this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];

                            }

                        }

                    }

                    return true;

     

                }

                return base.ProcessDialogKey(keyData);

            }

            protected override bool ProcessDataGridViewKey(KeyEventArgs e)

            {

                if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Right || e.KeyCode == Keys.Down)

                {

                    SendKeys.Send("{Tab}");

                    return true;

                }

                else if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Up)

                {

                    return true;

                }

                if (e.KeyData == Keys.Tab)

                {

                    int col = this.CurrentCell.ColumnIndex + 1;

                    for (; col < this.Columns.Count; col++)

                    {

                        if (!this.Columns[col].ReadOnly)

                        { break; }

                    }

                    if (col < this.Columns.Count)

                    {

                        this.CurrentCell =this.Rows[this.CurrentCell.RowIndex].Cells[col];

                    }

                    else

                    {

                        if (this.CurrentCell.RowIndex != this.Rows.Count - 1)

                        {

                            for (col = 0; col <= this.CurrentCell.ColumnIndex;col++)

                            {

                                if (!this.Columns[col].ReadOnly)

                                {

                                    break;

                                }

                            }

                            if (col <= this.CurrentCell.ColumnIndex)

                            {

                                this.CurrentCell =this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];

                            }

                        }

                    }

                    return true;

                }

                return base.ProcessDataGridViewKey(e);

            }

     

            int WM_LBUTTONDOWN = 0x0201;

            int WM_LBUTTONDBLCLK = 0x0203;

            int MK_LBUTTON = 0x1;

     

            protected override void WndProc(ref Message m)

            {

                if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONDBLCLK)

                {

                    if (m.WParam.ToInt32() == MK_LBUTTON)

                    {

                        int lparam = m.LParam.ToInt32();

                        int xpos = lparam & 0x0000FFFF;

                        int ypos = lparam >> 16;

                        if (!IsReadonlyCell(xpos, ypos))

                        {

                            base.WndProc(ref m);

                        }

                    }

                }

                else

                {

                    base.WndProc(ref m);

                }

     

            }

     

            private bool IsReadonlyCell(int xpos, int ypos)

            {

                int column = 0;

                for (; column < this.ColumnCount; column++)

                {

                    if (this.GetColumnDisplayRectangle(column,true).Contains(xpos, ypos))

                    {

                        break;

                    }

                }

               

                if (column < this.ColumnCount)

                {

                    if (this.Columns[column].ReadOnly)

                        return true;

                    else

                        return false;

                }

                else

                {

                    return false;

                }

            }

     

        }


    Use the derived DataGridView on your form.

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu

    • Proposed as answer by Tergiver Friday, April 17, 2009 8:48 PM
    • Marked as answer by Linda Liu Monday, April 20, 2009 3:12 AM
    Thursday, April 16, 2009 9:13 AM

All replies

  • Hi Cornel,

    To stop navigating to a readonly cell in a DataGridView via Tab, we could derive a new class from DataGridView and override the ProcessDialogKey and ProcessDataGridViewKey methods in the subclass.

     

    When the current cell in a DataGridView is in edit mode, and the user press a key, the override ProcessDialogKey method is called. When the current cell is not in edit mode, and the user press a key, the override ProcessDataGridViewKey method is called. So these two methods compensate each other.

     

    In the overrid ProcessDialogKey and ProcessDataGridViewKey methods, seek the next editable cell and if find then set it as the current cell.

     

    In addition, to prevent the user from selecting the readonly cells via mouse, we could override the WndProc method in the derived DataGridView class to catch the WM_LBUTTONDOWN and WM_LBUTTONDBLCLK messages. If the cell to be selected is readonly, discard the Windows message, so that the cell won't be selected; otherwise let the message go.

     

    The following is a sample:

     

    class MyDataGridView:DataGridView

        {

            protected override bool ProcessDialogKey(Keys keyData)

            {

                Keys key = (keyData & Keys.KeyCode);

     

                if (key == Keys.Enter ||  key == Keys.Right|| key == Keys.Down)

                {

                    SendKeys.Send("{Tab}");

                    return true;

                }

                else if (key == Keys.Left || key == Keys.Up )

                {

                    return true;

                }

                if (key == Keys.Tab)

                {

                    int col = this.CurrentCell.ColumnIndex + 1;

                    for (; col < this.Columns.Count; col++)

                    {

                        if (!this.Columns[col].ReadOnly)

                        { break; }

                    }

                    if (col < this.Columns.Count)

                    {

                        this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];

                    }

                    else

                    {

                        if (this.CurrentCell.RowIndex != this.Rows.Count - 1)

                        {

                            for (col = 0; col <= this.CurrentCell.ColumnIndex;col++)

                            {

                                if (!this.Columns[col].ReadOnly)

                                {

                                    break;

                                }

                            }

                            if (col <= this.CurrentCell.ColumnIndex)

                            {

                                this.CurrentCell =this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];

                            }

                        }

                    }

                    return true;

     

                }

                return base.ProcessDialogKey(keyData);

            }

            protected override bool ProcessDataGridViewKey(KeyEventArgs e)

            {

                if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Right || e.KeyCode == Keys.Down)

                {

                    SendKeys.Send("{Tab}");

                    return true;

                }

                else if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Up)

                {

                    return true;

                }

                if (e.KeyData == Keys.Tab)

                {

                    int col = this.CurrentCell.ColumnIndex + 1;

                    for (; col < this.Columns.Count; col++)

                    {

                        if (!this.Columns[col].ReadOnly)

                        { break; }

                    }

                    if (col < this.Columns.Count)

                    {

                        this.CurrentCell =this.Rows[this.CurrentCell.RowIndex].Cells[col];

                    }

                    else

                    {

                        if (this.CurrentCell.RowIndex != this.Rows.Count - 1)

                        {

                            for (col = 0; col <= this.CurrentCell.ColumnIndex;col++)

                            {

                                if (!this.Columns[col].ReadOnly)

                                {

                                    break;

                                }

                            }

                            if (col <= this.CurrentCell.ColumnIndex)

                            {

                                this.CurrentCell =this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];

                            }

                        }

                    }

                    return true;

                }

                return base.ProcessDataGridViewKey(e);

            }

     

            int WM_LBUTTONDOWN = 0x0201;

            int WM_LBUTTONDBLCLK = 0x0203;

            int MK_LBUTTON = 0x1;

     

            protected override void WndProc(ref Message m)

            {

                if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONDBLCLK)

                {

                    if (m.WParam.ToInt32() == MK_LBUTTON)

                    {

                        int lparam = m.LParam.ToInt32();

                        int xpos = lparam & 0x0000FFFF;

                        int ypos = lparam >> 16;

                        if (!IsReadonlyCell(xpos, ypos))

                        {

                            base.WndProc(ref m);

                        }

                    }

                }

                else

                {

                    base.WndProc(ref m);

                }

     

            }

     

            private bool IsReadonlyCell(int xpos, int ypos)

            {

                int column = 0;

                for (; column < this.ColumnCount; column++)

                {

                    if (this.GetColumnDisplayRectangle(column,true).Contains(xpos, ypos))

                    {

                        break;

                    }

                }

               

                if (column < this.ColumnCount)

                {

                    if (this.Columns[column].ReadOnly)

                        return true;

                    else

                        return false;

                }

                else

                {

                    return false;

                }

            }

     

        }


    Use the derived DataGridView on your form.

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu

    • Proposed as answer by Tergiver Friday, April 17, 2009 8:48 PM
    • Marked as answer by Linda Liu Monday, April 20, 2009 3:12 AM
    Thursday, April 16, 2009 9:13 AM
  • The above code will not work for backward navigation (i.e if we click on up arrow or left arrow or if we press Shift+Tab keys).
    To make backward navigation also to work properly, Use the following code:

        public partial class MyDataGridView : DataGridView
        {
            int WM_LBUTTONDOWN = 0x0201;
            int WM_LBUTTONDBLCLK = 0x0203;
            int MK_LBUTTON = 0x1;
            bool bShiftKey = false;
    
            public MyDataGridView()
            {
                InitializeComponent();
            }
    
            protected override bool ProcessDialogKey(Keys keyData)
            {
                Keys key = (keyData & Keys.KeyCode);
    
                if (key == Keys.ShiftKey || (int)keyData == 65545)
                    bShiftKey = true;
    
                if (key == Keys.Enter || key == Keys.Right || key == Keys.Down)
                {
                    SendKeys.Send("{Tab}");
                    return true;
                }
                else if (key == Keys.Left || key == Keys.Up)
                {
                    SendKeys.Send("+{Tab}");
                    return true;
                }
    
                if (!bShiftKey)
                {
                    if (key == Keys.Tab)
                    {
                        int col = this.CurrentCell.ColumnIndex + 1;
    
                        for (; col < this.Columns.Count; col++)
                        {
                            if (!this.Columns[col].ReadOnly)
                                break;
                        }
    
                        if (col < this.Columns.Count)
                            this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                        else
                        {
                            if (this.CurrentCell.RowIndex != this.Rows.Count - 1)
                            {
                                for (col = 0; col <= this.CurrentCell.ColumnIndex; col++)
                                {
                                    if (!this.Columns[col].ReadOnly)
                                        break;
                                }
    
                                try
                                {
                                    if (col <= this.CurrentCell.ColumnIndex)
                                        this.CurrentCell = this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];
                                }
                                catch
                                {
                                    this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                                }
                            }
                        }
                        return true;
                    }
                }
                else
                {
                    if (key == Keys.Tab)
                    {
                        int col = this.CurrentCell.ColumnIndex - 1;
    
                        for (; col < this.Columns.Count; col--)
                        {
                            if (col < 0 || !this.Columns[col].ReadOnly)
                                break;
                        }
    
                        if (col > -1)
                            this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                        else
                        {
                            if (this.CurrentCell.RowIndex != 0)
                            {
                                for (col = this.Columns.Count - 1; col >= this.CurrentCell.ColumnIndex; col--)
                                {
                                    if (col < 0 || !this.Columns[col].ReadOnly)
                                        break;
                                }
    
                                try
                                {
                                    if (col >= this.CurrentCell.ColumnIndex)
                                        this.CurrentCell = this.Rows[this.CurrentCell.RowIndex - 1].Cells[col];
                                }
                                catch
                                {
                                    this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                                }
                            }
                        }
                        bShiftKey = false;
                        return true;
                    }
                }
                return base.ProcessDialogKey(keyData);
            }
    
            protected override bool ProcessDataGridViewKey(KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Right || e.KeyCode == Keys.Down)
                {
                    SendKeys.Send("{Tab}");
                    return true;
                }
                else if ((e.Shift && e.KeyCode == Keys.Tab) || e.KeyCode == Keys.Left || e.KeyCode == Keys.Up)
                {
                    SendKeys.Send("+{Tab}");
                    return true;
                }
    
                if (!e.Shift)
                {
                    if (e.KeyData == Keys.Tab)
                    {
                        int col = this.CurrentCell.ColumnIndex + 1;
    
                        for (; col < this.Columns.Count; col++)
                        {
                            if (!this.Columns[col].ReadOnly)
                                break;
                        }
    
                        if (col < this.Columns.Count)
                            this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                        else
                        {
                            if (this.CurrentCell.RowIndex != this.Rows.Count - 1)
                            {
                                for (col = 0; col <= this.CurrentCell.ColumnIndex; col++)
                                {
                                    if (!this.Columns[col].ReadOnly)
                                        break;
                                }
    
                                if (col <= this.CurrentCell.ColumnIndex)
                                    this.CurrentCell = this.Rows[this.CurrentCell.RowIndex + 1].Cells[col];
                            }
                        }
                        return true;
                    }
                }
                else
                {
                    if (e.KeyData == Keys.Tab)
                    {
                        int col = this.CurrentCell.ColumnIndex - 1;
    
                        for (; col < this.Columns.Count; col--)
                        {
                            if (col < 0 || !this.Columns[col].ReadOnly)
                                break;
                        }
    
                        if (col > -1)
                            this.CurrentCell = this.Rows[this.CurrentCell.RowIndex].Cells[col];
                        else
                        {
                            if (this.CurrentCell.RowIndex != 0)
                            {
                                for (col = this.Columns.Count - 1; col >= this.CurrentCell.ColumnIndex; col--)
                                {
                                    if (col < 0 || !this.Columns[col].ReadOnly)
                                        break;
                                }
    
                                if (col >= this.CurrentCell.ColumnIndex)
                                    this.CurrentCell = this.Rows[this.CurrentCell.RowIndex - 1].Cells[col];
                            }
                        }
                        return true;
                    }
                }
                return base.ProcessDataGridViewKey(e);
            }
    
            protected override void WndProc(ref Message m)
            {
                if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONDBLCLK)
                {
                    if (m.WParam.ToInt32() == MK_LBUTTON)
                    {
                        int lparam = m.LParam.ToInt32();
                        int xpos = lparam & 0x0000FFFF;
                        int ypos = lparam >> 16;
    
                        if (!IsReadonlyCell(xpos, ypos))
                            base.WndProc(ref m);
                    }
                }
                else
                    base.WndProc(ref m);
            }
    
            private bool IsReadonlyCell(int xpos, int ypos)
            {
                int column = 0;
    
                for (; column < this.ColumnCount; column++)
                {
                    if (this.GetColumnDisplayRectangle(column, true).Contains(xpos, ypos))
                        break;
                }
    
                if (column < this.ColumnCount)
                {
                    if (this.Columns[column].ReadOnly)
                        return true;
                    else
                        return false;
                }
                else
                    return false;
            }
    
        }
    I have tested the above code and its working fine. If you find any issues, Please let me know.

    Thanks
    Pradeep KotamReddy

    Wednesday, December 2, 2009 10:05 AM
  • This was very helpful - thanks!  I found that setting CurrentCell to a hidden cell causes indigestion.  This has better up/down behavior as well as skipping hidden cells.

            protected override bool ProcessDialogKey(Keys keyData)
            {
                if (NavKey(keyData))
                    return true;        //handled
                return base.ProcessDialogKey(keyData);
            }
    
            protected override bool ProcessDataGridViewKey(KeyEventArgs e)
            {
                if (NavKey(e.KeyData))
                    return true;        //handled
                return base.ProcessDataGridViewKey(e);
            }
    
            bool NavKey(Keys keyData)
            {
                int col = this.CurrentCell.ColumnIndex;
                int row = this.CurrentCell.RowIndex;
                switch (keyData) {
                    case Keys.Down:
                        col--; row++;
                        goto case Keys.Right;    //fall through
                    case Keys.Right:
                    case Keys.Tab:
                    case Keys.Enter:
                        while (row < this.Rows.Count) {
                            while (++col < this.Columns.Count) {
                                if (!this[col, row].ReadOnly && this[col, row].Visible) {
                                    this.CurrentCell = this[col, row];
                                    return true;
                                }
                            }
                            col = -1;
                            row++;
                        }
                        return true;
    
                    case Keys.Up:
                        col++; row--;
                        goto case Keys.Left;    //fall through
                    case Keys.Left:
                    case Keys.Tab | Keys.Shift:
                    case Keys.Enter | Keys.Shift:
                        while (row >= 0) {
                            while (--col >= 0) {
                                if (!this[col, row].ReadOnly && this[col, row].Visible) {
                                    this.CurrentCell = this[col, row];
                                    return true;
                                }
                            }
                            col = this.Columns.Count;
                            row--;
                        }
                        return true;
                }
                return false;
            }
    
            const int WM_LBUTTONDOWN = 0x0201;
            const int WM_LBUTTONDBLCLK = 0x0203;
            const int MK_LBUTTON = 0x1;
            protected override void WndProc(ref Message m)
            {
                if ((m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONDBLCLK) && m.WParam.ToInt32() == MK_LBUTTON)
                {
                    int lparam = m.LParam.ToInt32();
                    int x = lparam & 0xFFFF;
                    int y = lparam >> 16;
                    HitTestInfo hti = HitTest(x, y);
                    if (hti.ColumnIndex >= 0 && hti.RowIndex >= 0 && Columns[hti.ColumnIndex].ReadOnly)
                        return;        //clicked in read-only cell - toss click event
                }
                base.WndProc(ref m);
            }
    
    Wednesday, December 23, 2009 2:05 AM
  • Thank you all for the code above - it has helped me a great deal, though I have found an issue with it -if anyone could enlighten me I would be very grateful...

    The above code is fine until you start validating input via the CellValidating() event. For example, if I'm validating a price field I could use the following code:

        private void dgvItems_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
          if (e.ColumnIndex == dgvItems.Columns["Quantity"].Index) {
            String value = Convert.ToString(e.FormattedValue);
            int dummy;
    
            if (!Int32.TryParse(value, out dummy)) {
              ArcMessageCode.ArcMessage("Not a valid quantity.", TamMode.amError);
              e.Cancel = true;
            }
          }
        }
    

    This works fine with the above code when exiting the column using Mouse clicks - if however you try to navigate away from the cell using Enter, Tab or any key (and the validation fails, i.e. e.Cancel is invoked) you get the following error:

    System.InvalidOperationException: Operation did not succeed because the program cannot commit or quit a cell value change.

    I'm assuming that this has something to do with Edit modes being switched, but any suggestions on how I could prevent this would be appreciated.

    Many Thanks,
    Martin Davies.

    Monday, March 14, 2011 11:06 AM
  • The below works based on the displayed index of a row.  Many other examples on the Internet I found do not use the displayed index.  I have found this to work well.

    Imports System.Windows.Forms

    Public Class ifDataGridView
        Inherits DataGridView


        Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
            If keyData = Keys.Tab Then
                If IsNothing(MyBase.CurrentCell) Then
                    Return True
                End If

                Dim nextColumn As DataGridViewColumn
                nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(MyBase.CurrentCell.ColumnIndex), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                If Not IsNothing(nextColumn) Then
                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(nextColumn.Index)
                Else
                    nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    If (MyBase.CurrentCell.RowIndex + 1) = MyBase.Rows.Count Then
                        MyBase.CurrentCell = MyBase.Rows(0).Cells(nextColumn.Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex + 1).Cells(nextColumn.Index)
                    End If
                End If

                Return True
            End If
            Return MyBase.ProcessDialogKey(keyData)
        End Function

        Protected Overrides Function ProcessDataGridViewKey(e As System.Windows.Forms.KeyEventArgs) As Boolean

            If e.KeyData = Keys.Tab And e.Shift = False Then

                If IsNothing(MyBase.CurrentCell) Then
                    Return True
                End If

                Dim nextColumn As DataGridViewColumn
                nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(MyBase.CurrentCell.ColumnIndex), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                If Not IsNothing(nextColumn) Then
                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(nextColumn.Index)
                Else
                    nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    If (MyBase.CurrentCell.RowIndex + 1) = MyBase.Rows.Count Then
                        MyBase.CurrentCell = MyBase.Rows(0).Cells(nextColumn.Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex + 1).Cells(nextColumn.Index)
                    End If
                End If

                Return True
            End If

            If e.KeyData = 65545 And e.Shift = True Then
                Dim nextColumn As DataGridViewColumn
                Dim priorColumn As DataGridViewColumn

                nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                priorColumn = nextColumn

                If nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex Then
                    If MyBase.CurrentCell.RowIndex > 0 Then
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.Rows.Count - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                    End If
                Else
                    'Same Row
                    Do Until nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex
                        priorColumn = nextColumn
                        nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(nextColumn.Index), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    Loop

                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(priorColumn.Index)
                End If
                Return True
            End If

            Return MyBase.ProcessDataGridViewKey(e)
        End Function
    End Class

    • Proposed as answer by HARDILUO Tuesday, September 17, 2019 3:58 PM
    Friday, October 14, 2011 6:23 PM
  • Hi Martin,

    I am facing the exact same scenario as you have/had. Is there any resolution for this at all?

    Many Thanks,

    Prag

    Friday, December 21, 2012 4:27 PM
  • If it were me, I would use a more object-oriented solution if possible. Overriding the ProcessDialogKey and ProcessDataGridViewKey methods is not the most object-oriented. I am sorry however that I do not have time to work out the details.

    Would it not work to derive from DataGridViewCell or something like that? Then if a cell is read-only and gets the focus then it could just pass the focus on to the next cell. That could continue until a cell is not read-only. That might provide poor perfornamce if there are very many read-only cells. There would need to be a way to know what direction to go; the tab key would need to be processed to determine that.



    Sam Hobbs
    SimpleSamples.Info

    Wednesday, January 2, 2013 2:18 AM
  • This is great. Thank you very much. Very helpful. I add some changes.

    Public Class CustomDGV
        Inherits DataGridView

        Protected Overrides Function ProcessDialogKey(keyData As System.Windows.Forms.Keys) As Boolean
            If keyData = Keys.Enter Or keyData = Keys.Tab Or keyData = Keys.Right Then
                If IsNothing(MyBase.CurrentCell) Then
                    Return True
                End If

                Dim nextColumn As DataGridViewColumn
                nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(MyBase.CurrentCell.ColumnIndex), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                If Not IsNothing(nextColumn) Then
                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(nextColumn.Index)
                Else
                    nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    If (MyBase.CurrentCell.RowIndex + 1) = MyBase.Rows.Count Then
                        MyBase.CurrentCell = MyBase.Rows(0).Cells(nextColumn.Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex + 1).Cells(nextColumn.Index)
                    End If
                End If

                Return True
            End If

            Return MyBase.ProcessDialogKey(keyData)
        End Function

        Protected Overrides Function ProcessDataGridViewKey(e As System.Windows.Forms.KeyEventArgs) As Boolean
            If e.KeyCode = Keys.Right Then
                If IsNothing(MyBase.CurrentCell) Then
                    Return True
                End If

                Dim nextColumn As DataGridViewColumn
                nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(MyBase.CurrentCell.ColumnIndex), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                If Not IsNothing(nextColumn) Then
                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(nextColumn.Index)
                Else
                    nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    If (MyBase.CurrentCell.RowIndex + 1) = MyBase.Rows.Count Then
                        MyBase.CurrentCell = MyBase.Rows(0).Cells(nextColumn.Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex + 1).Cells(nextColumn.Index)
                    End If
                End If

                Return True
            ElseIf e.KeyCode = Keys.Left Then
                Dim nextColumn As DataGridViewColumn
                Dim priorColumn As DataGridViewColumn

                nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                priorColumn = nextColumn

                If nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex Then
                    If MyBase.CurrentCell.RowIndex > 0 Then
                        MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                    Else
                        MyBase.CurrentCell = MyBase.Rows(MyBase.Rows.Count - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                    End If
                Else
                    'Same Row
                    Do Until nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex
                        priorColumn = nextColumn
                        nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(nextColumn.Index), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                    Loop

                    MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(priorColumn.Index)
                End If

                Return True
            Else
                If e.KeyCode = Keys.Enter Or e.KeyCode = Keys.Tab Or e.KeyData = 65545 Then
                    If e.Shift = False Then
                        If IsNothing(MyBase.CurrentCell) Then
                            Return True
                        End If

                        Dim nextColumn As DataGridViewColumn
                        nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(MyBase.CurrentCell.ColumnIndex), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                        If Not IsNothing(nextColumn) Then
                            MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(nextColumn.Index)
                        Else
                            nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                            If (MyBase.CurrentCell.RowIndex + 1) = MyBase.Rows.Count Then
                                MyBase.CurrentCell = MyBase.Rows(0).Cells(nextColumn.Index)
                            Else
                                MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex + 1).Cells(nextColumn.Index)
                            End If
                        End If

                        Return True
                    Else
                        Dim nextColumn As DataGridViewColumn
                        Dim priorColumn As DataGridViewColumn

                        nextColumn = MyBase.Columns.GetFirstColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                        priorColumn = nextColumn

                        If nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex Then
                            If MyBase.CurrentCell.RowIndex > 0 Then
                                MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                            Else
                                MyBase.CurrentCell = MyBase.Rows(MyBase.Rows.Count - 1).Cells(MyBase.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly).Index)
                            End If
                        Else
                            'Same Row
                            Do Until nextColumn.DisplayIndex >= MyBase.Columns(MyBase.CurrentCell.ColumnIndex).DisplayIndex
                                priorColumn = nextColumn
                                nextColumn = MyBase.Columns.GetNextColumn(MyBase.Columns(nextColumn.Index), DataGridViewElementStates.Visible, DataGridViewElementStates.ReadOnly)
                            Loop

                            MyBase.CurrentCell = MyBase.Rows(MyBase.CurrentCell.RowIndex).Cells(priorColumn.Index)
                        End If

                        Return True
                    End If
                End If
            End If

            Return MyBase.ProcessDataGridViewKey(e)
        End Function
    End Class

    Tuesday, September 17, 2019 3:57 PM