diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.AccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.AccessibleObject.cs index 4763f44de10..8df8f01df36 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.AccessibleObject.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.AccessibleObject.cs @@ -32,6 +32,26 @@ private bool IsModal } } + internal void ReleaseChildUiaProviders() + { + if (!OsVersion.IsWindows8OrGreater()) + { + return; + } + + if (_topRowAccessibilityObject is not null) + { + UiaCore.UiaDisconnectProvider(_topRowAccessibilityObject); + _topRowAccessibilityObject = null; + } + + if (_selectedCellsAccessibilityObject is not null) + { + UiaCore.UiaDisconnectProvider(_selectedCellsAccessibilityObject); + _selectedCellsAccessibilityObject = null; + } + } + public override AccessibleRole Role { get diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.Methods.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.Methods.cs index bc2ccbe39ee..a87cb463508 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.Methods.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridView.Methods.cs @@ -26104,6 +26104,44 @@ private void ReleaseMouse() Capture = false; } + internal override void ReleaseUiaProvider(IntPtr handle) + { + if (!IsAccessibilityObjectCreated) + { + return; + } + + if (OsVersion.IsWindows8OrGreater()) + { + foreach (DataGridViewRow row in Rows) + { + foreach (DataGridViewCell cell in row.Cells) + { + cell.ReleaseUiaProvider(); + } + + row.HeaderCell.ReleaseUiaProvider(); + row.ReleaseUiaProvider(); + } + + foreach (DataGridViewColumn column in Columns) + { + column.HeaderCell.ReleaseUiaProvider(); + } + + _editingPanel?.ReleaseUiaProvider(IntPtr.Zero); + _editingPanelAccessibleObject = null; + _topLeftHeaderCell?.ReleaseUiaProvider(); + + if (AccessibilityObject is DataGridViewAccessibleObject accessibleObject) + { + accessibleObject.ReleaseChildUiaProviders(); + } + } + + base.ReleaseUiaProvider(handle); + } + private void RemoveIndividualReadOnlyCellsInColumn(int columnIndex) { int cellIndex = 0; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewCell.cs index 2ece3e53deb..9839945c2be 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewCell.cs @@ -491,6 +491,8 @@ public DataGridViewCellStyle InheritedStyle } } + internal bool IsAccessibilityObjectCreated => Properties.GetObject(s_propCellAccessibilityObject) is AccessibleObject; + /// /// Indicates whether or not the parent grid view for this element has an accessible object associated with it. /// @@ -1292,8 +1294,9 @@ private bool AccessibleRestructuringNeeded Type editingControlType = DataGridView.EditingControl.GetType(); return - (editingControlType == typeof(DataGridViewComboBoxEditingControl) && !editingControlType.IsSubclassOf(typeof(DataGridViewComboBoxEditingControl))) || - (editingControlType == typeof(DataGridViewTextBoxEditingControl) && !editingControlType.IsSubclassOf(typeof(DataGridViewTextBoxEditingControl))); + IsAccessibilityObjectCreated && + ((editingControlType == typeof(DataGridViewComboBoxEditingControl) && !editingControlType.IsSubclassOf(typeof(DataGridViewComboBoxEditingControl))) || + (editingControlType == typeof(DataGridViewTextBoxEditingControl) && !editingControlType.IsSubclassOf(typeof(DataGridViewTextBoxEditingControl)))); } } @@ -4056,6 +4059,21 @@ public virtual Rectangle PositionEditingPanel(Rectangle cellBounds, return new Rectangle(xEditingControl, yEditingControl, wEditingControl, hEditingControl); } + internal virtual void ReleaseUiaProvider() + { + if (!IsAccessibilityObjectCreated) + { + return; + } + + if (OsVersion.IsWindows8OrGreater()) + { + UiaCore.UiaDisconnectProvider(AccessibilityObject); + } + + Properties.SetObject(s_propCellAccessibilityObject, null); + } + protected virtual bool SetValue(int rowIndex, object value) { object originalValue = null; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewColumnCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewColumnCollection.cs index 8fe4e851878..c596e5cac85 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewColumnCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewColumnCollection.cs @@ -1109,6 +1109,17 @@ internal void RemoveAtInternal(int index, bool force) Debug.Assert(!DataGridView.InDisplayIndexAdjustments); DataGridViewColumn dataGridViewColumn = _items[index]; + + if (DataGridView.IsAccessibilityObjectCreated && OsVersion.IsWindows8OrGreater()) + { + foreach (DataGridViewRow row in DataGridView.Rows) + { + row.Cells[index].ReleaseUiaProvider(); + } + + dataGridViewColumn.HeaderCell.ReleaseUiaProvider(); + } + DataGridView.OnRemovingColumn(dataGridViewColumn, out Point newCurrentCell, force); InvalidateCachedColumnsOrder(); _items.RemoveAt(index); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxCell.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxCell.cs index 81bafb606fb..2d60af10b07 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxCell.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxCell.cs @@ -2547,6 +2547,13 @@ public override object ParseFormattedValue( } } + internal override void ReleaseUiaProvider() + { + EditingComboBox?.ReleaseUiaProvider(IntPtr.Zero); + + base.ReleaseUiaProvider(); + } + /// /// Gets the row Index and column Index of the cell. /// diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.DataGridViewComboBoxEditingControlAccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.DataGridViewComboBoxEditingControlAccessibleObject.cs index 2d58f053266..1efffb74e4e 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.DataGridViewComboBoxEditingControlAccessibleObject.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.DataGridViewComboBoxEditingControlAccessibleObject.cs @@ -26,6 +26,11 @@ public DataGridViewComboBoxEditingControlAccessibleObject(DataGridViewComboBoxEd _ownerControl = ownerControl; } + internal void ClearParent() + { + _parentAccessibleObject = null; + } + public override AccessibleObject? Parent { get diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.cs index d4841ed5f45..58aa8c5d7ba 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewComboBoxEditingControl.cs @@ -163,7 +163,20 @@ protected override void OnHandleCreated(EventArgs e) base.OnHandleCreated(e); // The null-check was added as a fix for a https://github.com/dotnet/winforms/issues/2138 - _dataGridView?.SetAccessibleObjectParent(AccessibilityObject); + if (_dataGridView?.IsAccessibilityObjectCreated == true) + { + _dataGridView.SetAccessibleObjectParent(AccessibilityObject); + } + } + + internal override void ReleaseUiaProvider(nint handle) + { + if (TryGetAccessibilityObject(out AccessibleObject accessibleObject)) + { + ((DataGridViewComboBoxEditingControlAccessibleObject)accessibleObject).ClearParent(); + } + + base.ReleaseUiaProvider(handle); } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs index d28779448c5..f2f5760b1c8 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRow.cs @@ -242,6 +242,8 @@ public override DataGridViewCellStyle InheritedStyle } } + internal bool IsAccessibilityObjectCreated => Properties.GetObject(s_propRowAccessibilityObject) is AccessibleObject; + [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsNewRow @@ -1728,6 +1730,21 @@ protected internal virtual void PaintHeader(Graphics graphics, } } + internal void ReleaseUiaProvider() + { + if (!IsAccessibilityObjectCreated) + { + return; + } + + if (OsVersion.IsWindows8OrGreater()) + { + Interop.UiaCore.UiaDisconnectProvider(AccessibilityObject); + } + + Properties.SetObject(s_propRowAccessibilityObject, null); + } + internal void SetReadOnlyCellCore(DataGridViewCell dataGridViewCell, bool readOnly) { Debug.Assert(Index == -1); diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRowCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRowCollection.cs index 11122450ff8..f02f5f56e0d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRowCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewRowCollection.cs @@ -2259,6 +2259,17 @@ public virtual void RemoveAt(int index) throw new InvalidOperationException(SR.DataGridView_ForbiddenOperationInEventHandler); } + if (DataGridView.IsAccessibilityObjectCreated && OsVersion.IsWindows8OrGreater() && this[index] is DataGridViewRow row) + { + foreach (DataGridViewCell cell in row.Cells) + { + cell.ReleaseUiaProvider(); + } + + row.HeaderCell.ReleaseUiaProvider(); + row.ReleaseUiaProvider(); + } + if (DataGridView.DataSource is not null) { if (DataGridView.DataConnection.List is IBindingList list && list.AllowRemove && list.SupportsChangeNotification) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.DataGridViewTextBoxEditingControlAccessibleObject.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.DataGridViewTextBoxEditingControlAccessibleObject.cs index f6d0dd1b8f5..de1e1a5d04d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.DataGridViewTextBoxEditingControlAccessibleObject.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.DataGridViewTextBoxEditingControlAccessibleObject.cs @@ -21,6 +21,11 @@ internal class DataGridViewTextBoxEditingControlAccessibleObject : TextBoxBaseAc public DataGridViewTextBoxEditingControlAccessibleObject(DataGridViewTextBoxEditingControl ownerControl) : base(ownerControl) { } + internal void ClearParent() + { + _parentAccessibleObject = null; + } + public override AccessibleObject? Parent => _parentAccessibleObject; public override string Name => Owner.AccessibleName ?? SR.DataGridView_AccEditingControlAccName; diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.cs b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.cs index fed54b5f74c..9294de5237f 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/DataGridViewTextBoxEditingControl.cs @@ -90,8 +90,6 @@ public virtual bool RepositionEditingControlOnValueChange } } - internal override bool SupportsUiaProviders => true; - public virtual void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) { ArgumentNullException.ThrowIfNull(dataGridViewCellStyle); @@ -287,6 +285,16 @@ protected override bool ProcessKeyEventArgs(ref Message m) return base.ProcessKeyEventArgs(ref m); } + internal override void ReleaseUiaProvider(nint handle) + { + if (TryGetAccessibilityObject(out AccessibleObject? accessibleObject)) + { + ((DataGridViewTextBoxEditingControlAccessibleObject)accessibleObject).ClearParent(); + } + + base.ReleaseUiaProvider(handle); + } + private static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align) { if ((align & AnyRight) != 0) @@ -306,10 +314,11 @@ private static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignme protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); - if (IsHandleCreated) + + // The null-check was added as a fix for a https://github.com/dotnet/winforms/issues/2138 + if (IsHandleCreated && _dataGridView?.IsAccessibilityObjectCreated == true) { - // The null-check was added as a fix for a https://github.com/dotnet/winforms/issues/2138 - _dataGridView?.SetAccessibleObjectParent(AccessibilityObject); + _dataGridView.SetAccessibleObjectParent(AccessibilityObject); } } }