Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25593,6 +25593,23 @@ private void ReleaseMouse()
Capture = false;
}

private static void ReleaseRowUiaProviders(DataGridViewRow row)
{
if (!row.IsAccessibilityObjectCreated)
{
return;
}

DataGridViewCellCollection cells = row.Cells;
for (int cellIndex = 0; cellIndex < cells.Count; cellIndex++)
{
cells[cellIndex].ReleaseUiaProvider();
}

row.HeaderCell.ReleaseUiaProvider();
row.ReleaseUiaProvider();
}

internal override void ReleaseUiaProvider(HWND handle)
{
if (!IsAccessibilityObjectCreated)
Expand All @@ -25602,17 +25619,22 @@ internal override void ReleaseUiaProvider(HWND handle)

if (OsVersion.IsWindows8OrGreater())
{
foreach (DataGridViewRow row in Rows)
// Collect unique rows from SharedList using HashSet for deduplication.
// SharedList may have several hundred thousand entries, but most point to the same shared row instances.
HashSet<DataGridViewRow> uniqueRows = [];
List<DataGridViewRow> sharedList = Rows.SharedList;
for (int i = 0; i < sharedList.Count; i++)
{
foreach (DataGridViewCell cell in row.Cells)
{
cell.ReleaseUiaProvider();
}
uniqueRows.Add(sharedList[i]);
}

row.HeaderCell.ReleaseUiaProvider();
row.ReleaseUiaProvider();
// Release UIA providers for unique rows
foreach (DataGridViewRow row in uniqueRows)
{
ReleaseRowUiaProviders(row);
}

// Release column header accessibility objects
foreach (DataGridViewColumn column in Columns)
{
column.HeaderCell.ReleaseUiaProvider();
Expand All @@ -25621,7 +25643,6 @@ internal override void ReleaseUiaProvider(HWND handle)
_editingPanel?.ReleaseUiaProvider(HWND.Null);
_editingPanelAccessibleObject = null;
_topLeftHeaderCell?.ReleaseUiaProvider();

if (AccessibilityObject is DataGridViewAccessibleObject accessibleObject)
{
accessibleObject.ReleaseChildUiaProviders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,16 @@ internal void RemoveAtInternal(int index, bool force)

if (DataGridView.IsAccessibilityObjectCreated && OsVersion.IsWindows8OrGreater())
{
foreach (DataGridViewRow row in DataGridView.Rows)
// Collect unique rows from SharedList using HashSet for deduplication.
HashSet<DataGridViewRow> uniqueRows = [];
List<DataGridViewRow> sharedList = DataGridView.Rows.SharedList;
for (int i = 0; i < sharedList.Count; i++)
{
uniqueRows.Add(sharedList[i]);
}

// Release UIA providers for the cell at the removed column index
foreach (DataGridViewRow row in uniqueRows.Where(row => row.IsAccessibilityObjectCreated))
{
row.Cells[index].ReleaseUiaProvider();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,6 @@ public DataGridViewRowAccessibleObject(DataGridViewRow owner)
_owningDataGridViewRow = owner;
}

/// <summary>
/// Returns the index of the row, taking into account the invisibility of other rows.
/// </summary>
private int VisibleIndex
=> _owningDataGridViewRow?.DataGridView is DataGridView dataGridView
? dataGridView.ColumnHeadersVisible
? dataGridView.Rows.GetVisibleIndex(_owningDataGridViewRow) + 1
: dataGridView.Rows.GetVisibleIndex(_owningDataGridViewRow)
: -1;

public override Rectangle Bounds
{
get
Expand Down Expand Up @@ -338,35 +328,39 @@ dataGridView.CurrentCell is not null &&
{
case AccessibleNavigation.Down:
case AccessibleNavigation.Next:
if (_owningDataGridViewRow.Index != _owningDataGridViewRow.DataGridView.Rows.GetLastRow(DataGridViewElementStates.Visible))
{
int visibleIndex = VisibleIndex;
return visibleIndex < 0
? null
: _owningDataGridViewRow.DataGridView.AccessibilityObject.GetChild(visibleIndex + 1);
}
else
DataGridView dataGridView = _owningDataGridViewRow.DataGridView;
int nextDisplayed = dataGridView.Rows.GetNextRow(_owningDataGridViewRow.Index, DataGridViewElementStates.Displayed);
if (nextDisplayed == -1)
{
return null;
}

return dataGridView.Rows[nextDisplayed].AccessibilityObject;

case AccessibleNavigation.Up:
case AccessibleNavigation.Previous:
if (_owningDataGridViewRow.Index != _owningDataGridViewRow.DataGridView.Rows.GetFirstRow(DataGridViewElementStates.Visible))
{
return _owningDataGridViewRow.DataGridView.AccessibilityObject.GetChild(VisibleIndex - 1);
}
else if (_owningDataGridViewRow.DataGridView.ColumnHeadersVisible)
dataGridView = _owningDataGridViewRow.DataGridView;
int current = _owningDataGridViewRow.Index;
int previousDisplayed = dataGridView.Rows.GetPreviousRow(current, DataGridViewElementStates.Displayed);
if (previousDisplayed != -1)
{
// return the top row header acc obj
return ParentPrivate?.GetChild(0);
return _owningDataGridViewRow.DataGridView.Rows[previousDisplayed].AccessibilityObject;
}
else

if (_owningDataGridViewRow.DataGridView.RowHeadersVisible)
{
// if this is the first row and the DataGridView RowHeaders are not visible return null;
return null;
var headerCell = _owningDataGridViewRow.DataGridView.Rows[current].HeaderCell;
if (headerCell is not null)
{
// Directly return the row header cell's AccessibleObject.
// This avoids container child-index access (no GetChild(i)).
return headerCell.AccessibilityObject;
}
}

// if this is the first row and the DataGridView RowHeaders are not visible return null;
return null;

case AccessibleNavigation.FirstChild:
if (GetChildCount() == 0)
{
Expand Down
Loading