Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4001940
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 20, 20262026-05-20T07:57:56+00:00 2026-05-20T07:57:56+00:00

I have a DataGridView in C# (.NET 2.0) with a few read-only cells (3

  • 0

I have a DataGridView in C# (.NET 2.0) with a few read-only cells (3 out of 25). I’m using the method outlined in the top answer here to set ReadOnly on those specific cells in the Form_Load handler. The linked question states that

some cells has to be ReadOnly and also when the user navigates with TAB or ENTER between cells, the ReadOnly cells should be bypassed

so I assumed setting the flag would cause the cells to be skipped.

Long story short, it’s not. The read-only cells get tabbed to and selected even though they cannot be edited. I’m combing over the properties of the DataGridView looking for some kind of TabMode or TabSkipsReadOnlyCells property, but so far nothing. Is there a property to set for this behavior, or do I have to write some tab event handling code of some kind?

This seems like it should be the default behavior, so I’m kind of annoyed to even have to find a property for it, much less have to write code to do it…

EDIT: I should clarify, I’m not interested in only handling navigation with the Tab key. I want to implement reasonable navigation with the arrow keys and possibly the mouse as well. That means if I have to write code I need direct control over where the selection moves when I bounce it out of a read-only cell, probably by setting CurrentCell on the DataGridView. This is so that if the user up-arrows into a read-only cell I can redirect to the cell above, not always to the cell to the right.

EDIT 2: Here’s my final solution, handling arrow key navigation as well as tab navigation, based on Sean Griffiths’ code (also linked in the accepted answer):

private void GridForm_Load(object sender, EventArgs e)
{
    dataGridView1.CellEnter += dataGridView1_CellEnter;
}

//a delegate is needed to avoid a circular loop when selecting a cell when in a cell selection event
private delegate void SetColumnAndRowOnGrid(DataGridView grid, int columnIndex, int rowIndex);
static SetColumnAndRowOnGrid setCellMethod = new SetColumnAndRowOnGrid(setGridCell);

// Method pointed to by the delegate
private static void setGridCell(DataGridView grid, int columnIndex, int rowIndex)
{
    grid.CurrentCell = grid.Rows[rowIndex].Cells[columnIndex];
    grid.BeginEdit(true);
}

// Track the cell we leave so we can determine direction of "travel"
int _lastRow = 0, _lastCol = 0;
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
    _lastRow = e.RowIndex;
    _lastCol = e.ColumnIndex;
}

enum Direction { Up, Down, Left, Right }

// When we enter a read only cell, determine direction 
// of "travel" and keep going that way
private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
    int currRow = e.RowIndex;
    int currCol = e.ColumnIndex;
    if (dataGridView1.Rows[currRow].Cells[currCol].ReadOnly)
    {
        Direction direction = Direction.Right;
        if ((currRow != _lastRow) && (currCol == _lastCol))
        {
            // moving vertically
            if (currRow < _lastRow) direction = Direction.Up;
            else direction = Direction.Down;
        }
        else
        {
            // moving horizontally
            if (currCol == 0 &&
                _lastCol == dataGridView1.Columns.Count - 1 &&
                currRow == _lastRow + 1)
            {
                // Special case - probably just tabbed from end of row
                direction = Direction.Right;
            }
            else if (currCol == dataGridView1.Columns.Count - 1 &&
                _lastCol == 0 &&
                currRow == _lastRow - 1)
            {
                // Special case - probably just shift-tabbed from start of row
                direction = Direction.Left;
            }
            else if (currCol < _lastCol) { direction = Direction.Left; }
        }
        //this cell is readonly, find the next tabable cell
        if (!SetNextTabableCell(dataGridView1, currCol, currRow, direction))
        {
            // All the cells in the grid have been tried, none could be tabbed
            // to so move onto the next control
            bool tabForward = direction == Direction.Right || direction == Direction.Down;
            SelectNextControl(this, tabForward, true, true, true);
        }
    }
}

// Find the next cell that we want to be selectable
private static bool SetNextTabableCell(DataGridView grid, int nextColumn, int nextRow, Direction direction)
{
    //keep selecting each next cell until one is found that isn't either readonly or invisible
    int maxMoves = grid.ColumnCount * grid.RowCount;
    int moves = 0;
    do
    {
        if (!GetNextCell(grid, ref nextColumn, ref nextRow, ref direction)) return false;
        // Prevent infinite loop - I managed to get in one when this function
        // wound up in a readonly column with a direction of Down (if we've moved
        // to another cell more times than there are cells in the grid, just give up)
        if (++moves > maxMoves) return false;
    }
    while (grid.Rows[nextRow].Cells[nextColumn].ReadOnly == true ||
                grid.Rows[nextRow].Cells[nextColumn].Visible == false);

    //a cell has been found that can be entered, use the delegate to select it
    grid.BeginInvoke(setCellMethod, grid, nextColumn, nextRow);
    return true;
}

// Get the next cell in the indicated direction
// Wrap around if going left-right
// Bounce at the edge if going up/down
private static bool GetNextCell(DataGridView grid, ref int nextColumn, ref int nextRow, ref Direction direction)
{
    switch (direction)
    {
        case Direction.Right:
            if (nextColumn < grid.Columns.Count - 1)
            {
                // Nominal case - move right one cell
                nextColumn = nextColumn + 1;
            }
            else // at the last column
            {
                // go the the first column
                nextColumn = 0;
                if (nextRow < grid.Rows.Count - 1)
                {
                    // Nominal case - move down one row
                    nextRow = nextRow + 1;
                }
                // at the last row and last column exit this method, no cell can be selected
                else { return false; }
            }
            break;
        case Direction.Left:
            if (nextColumn > 0)
            {
                // Nominal case - move left one cell
                nextColumn = nextColumn - 1;
            }
            else // at the first column
            {
                // go the the last column
                nextColumn = grid.Columns.Count - 1;
                if (nextRow > 0)
                {
                    // Nominal case - move up one row
                    nextRow = nextRow - 1;
                }
                // at the first row and first column exit this method, no cell can be selected
                else { return false; }
            }
            break;
        case Direction.Down:
            if (nextRow < grid.Rows.Count - 1)
            {
                // Nominal case - move down one cell
                nextRow = nextRow + 1;
            }
            else // at the last row
            {
                // turn around
                nextRow = nextRow - 1;
                direction = Direction.Up;
            }
            break;
        case Direction.Up:
            if (nextRow > 0)
            {
                // Nominal case - move up one cell
                nextRow = nextRow - 1;
            }
            else // at the first row
            {
                // turn around
                nextRow = nextRow + 1;
                direction = Direction.Down;
            }
            break;
        default: return false;
    }
    return true;
}

If anyone uses this and finds cases where it behaves badly, I’d like to hear about it so I can hopefully update this with a fix.

EDIT 3: Added a safety counter after the code managed to get itself in an infinite-loop state today. All cells in column zero were set to read-only, and the first click into the grid control was in column zero, so it tried to move down, then up, then down….

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-20T07:57:57+00:00Added an answer on May 20, 2026 at 7:57 am

    I had a similar problem using a datagridview – there is a write up on my solution here http://codemumbler.blogspot.com/2011/02/one-aspect-of-datagridviews-that-you.html

    It uses the CellEnter eventhandler and hunts for the next available usable sell in the grid and uses a delegate to avoid a Reentrant exception.

    Hope this helps – Sean

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a .NET windows app. I have a DataGridView which has a few
I have a DataGridView with its datasource set to a generic list of custom
I have a DataGridView that I want to query using Linq (C# WinForm). I
I have a DataGridView form in my .NET application and I'd like to be
I have an app that I wrote using C# .NET 4.0 in Visual Studio
I have a DataGridView with one DataGridViewComboBoxColumn in my WinForms application. I need to
I have a datagridview where the users can select which subset of columns to
I have a datagridview which im binding DataTable to. What I want do is
I have a DataGridView control in a winforms app that I'm working on. The
I have a DataGridView binded to this table: [Users] ID Name -- ---- 11

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.