Skip to content

When DataGridView has a lot of rows, selecting row near bottom of DataGridView is very slow #15171

Description

@hjin1113-web

.NET version

10.0.12

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No response

Issue description

Very easy to reproduce. Using following codes. Scroll down to the bottom. Select any row. It will take seconds to select a row.

        private void Form1_Load(object sender, EventArgs e)
        {
            DataGridView Tester = new DataGridView();
            Tester.Columns.Add("trest", "trstr");
            for (int i = 0; i < 30000; i++)
            {
                Tester.Rows.Add($"Row {i:00000}");
            }

            Tester.Visible = true;
            Tester.Dock = DockStyle.Fill;
            this.Controls.Add(Tester);
       }

The bug is in DataGridViewRowCollection. GetVisibleIndex repeats Count (30001) and DisplayIndexToRowIndex also repeats Count (30001).

    internal int GetVisibleIndex(DataGridViewRow row)
    {
        for (int i = 0; i < Count; i++)
        {
            int index = DisplayIndexToRowIndex(i);
            if (index != -1 && _items[index] == row)
            {
                return i;
            }
        }

        return -1;
    }

    internal int DisplayIndexToRowIndex(int visibleRowIndex)
    {
        Debug.Assert(visibleRowIndex < GetRowCount(DataGridViewElementStates.Visible));

        // go row by row
        // the alternative would be to do a binary search using DataGridViewRowCollection::GetRowCount(...)
        // but that method also iterates thru each row so we would not gain much
        int indexOfCurrentVisibleRow = -1;
        for (int i = 0; i < Count; i++)
        {
            if ((GetRowState(i) & DataGridViewElementStates.Visible) == DataGridViewElementStates.Visible)
            {
                indexOfCurrentVisibleRow++;
            }

            if (indexOfCurrentVisibleRow == visibleRowIndex)
            {
                return i;
            }
        }

        Debug.Assert(false, "we should have found the row already");
        return -1;
    }

GetVisibleIndex is called by DataGridViewCellAccessibleObject:Name
Following codes bypass the performance issue.

        private void Form1_Load(object sender, EventArgs e)
        {
            DataGridView Tester = new DataGridView();
            Tester.Columns.Add("trest", "trstr");
            for (int i = 0; i < 30000; i++)
            {
                DataGridViewRow row = new DataGridViewRow();
                NoAccessCell cell = new NoAccessCell();
                cell.Value = $"Row {i:00000}";
                row.Cells.Add(cell);
                Tester.Rows.Add(row);
            }

            Tester.Visible = true;
            Tester.Dock = DockStyle.Fill;
            this.Controls.Add(Tester);
        }
    class NoAccessCell : DataGridViewTextBoxCell
    {
        protected override AccessibleObject CreateAccessibilityInstance()
        {
            return new NoAccessibilityObject();
        }
    }
    class NoAccessibilityObject : AccessibleObject
    {
        public override string Name
        {
            get => null;
            set { }
        }

        public override AccessibleRole Role => AccessibleRole.None;

        public override AccessibleObject GetChild(int index) => null;
        public override int GetChildCount() => 0;

        public override Rectangle Bounds => Rectangle.Empty;

        public override void DoDefaultAction() { }
    }

Steps to reproduce

Very easy to reproduce. Using following codes. Scroll down to the bottom. Select any row. It will take seconds to select a row.

        private void Form1_Load(object sender, EventArgs e)
        {
            DataGridView Tester = new DataGridView();
            Tester.Columns.Add("trest", "trstr");
            for (int i = 0; i < 30000; i++)
            {
                Tester.Rows.Add($"Row {i:00000}");
            }

            Tester.Visible = true;
            Tester.Dock = DockStyle.Fill;
            this.Controls.Add(Tester);
       }

Activity

  1. added
    untriagedThe team needs to look at this issue in the next triage
    on Sep 22, 2026
  2. self-assigned this
    on Sep 22, 2026
  3. added
    tenet-accessibilityMAS violation, UIA issue; problems with accessibility standards
    and removed
    untriagedThe team needs to look at this issue in the next triage
    on Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

tenet-accessibilityMAS violation, UIA issue; problems with accessibility standards

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions