// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using Windows.Win32.System.Variant; using Windows.Win32.UI.Accessibility; namespace System.Windows.Forms; public partial class DataGridViewRowHeaderCell { protected class DataGridViewRowHeaderCellAccessibleObject : DataGridViewCellAccessibleObject { public DataGridViewRowHeaderCellAccessibleObject(DataGridViewRowHeaderCell? owner) : base(owner) { } public override Rectangle Bounds { get { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.DataGridView is null || Owner.OwningRow is null || ParentPrivate is null) { return Rectangle.Empty; } // use the parent row acc obj bounds Rectangle rowRect = ParentPrivate.Bounds; Rectangle cellRect = rowRect; cellRect.Width = Owner.DataGridView.RowHeadersWidth; if (Owner.DataGridView.RightToLeft == RightToLeft.Yes) { cellRect.X = rowRect.Right - cellRect.Width; } return cellRect; } } public override string DefaultAction { get { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.DataGridView is not null && (Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.FullRowSelect || Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.RowHeaderSelect)) { return SR.DataGridView_RowHeaderCellAccDefaultAction; } return string.Empty; } } public override string? Name => ParentPrivate?.Name ?? string.Empty; public override AccessibleObject? Parent => ParentPrivate; private AccessibleObject? ParentPrivate { get { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } return Owner.OwningRow?.AccessibilityObject; } } public override AccessibleRole Role => AccessibleRole.RowHeader; public override AccessibleStates State { get { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } AccessibleStates resultState = AccessibleStates.Selectable; // get the Offscreen state from the base method. AccessibleStates state = base.State; if ((state & AccessibleStates.Offscreen) == AccessibleStates.Offscreen) { resultState |= AccessibleStates.Offscreen; } if (Owner.DataGridView is not null && (Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.FullRowSelect || Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.RowHeaderSelect)) { if (Owner.OwningRow is not null && Owner.OwningRow.Selected) { resultState |= AccessibleStates.Selected; } } return resultState; } } public override string Value => string.Empty; public override void DoDefaultAction() { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.DataGridView?.IsHandleCreated == true && Owner.OwningRow is not null && (Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.FullRowSelect || Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.RowHeaderSelect)) { Owner.OwningRow.Selected = true; } } public override AccessibleObject? Navigate(AccessibleNavigation navigationDirection) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.OwningRow is null || Owner.DataGridView is null) { return null; } switch (navigationDirection) { case AccessibleNavigation.Next: return (Owner.DataGridView.Columns.GetColumnCount(DataGridViewElementStates.Visible) > 0) ? ParentPrivate?.GetChild(1) // go to the next sibling : null; case AccessibleNavigation.Down: { if (Owner.OwningRow.Index == Owner.DataGridView.Rows.GetLastRow(DataGridViewElementStates.Visible)) { return null; } int nextVisibleRow = Owner.DataGridView.Rows.GetNextRow(Owner.OwningRow.Index, DataGridViewElementStates.Visible); int actualDisplayIndex = Owner.DataGridView.Rows.GetRowCount(DataGridViewElementStates.Visible, 0, nextVisibleRow); if (Owner.DataGridView.ColumnHeadersVisible) { // Add 1 because the first child in the data grid view acc obj is the top row header acc obj actualDisplayIndex++; } return Owner.DataGridView.AccessibilityObject.GetChild(actualDisplayIndex)?.GetChild(0); } case AccessibleNavigation.Up: { if (Owner.OwningRow.Index == Owner.DataGridView.Rows.GetFirstRow(DataGridViewElementStates.Visible)) { if (!Owner.DataGridView.ColumnHeadersVisible) { return null; } // Return the top left header cell accessible object. Debug.Assert(Owner.DataGridView.TopLeftHeaderCell.AccessibilityObject == Owner.DataGridView.AccessibilityObject.GetChild(0)!.GetChild(0)); return Owner.DataGridView.AccessibilityObject.GetChild(0)?.GetChild(0); } else { int previousVisibleRow = Owner.DataGridView.Rows.GetPreviousRow(Owner.OwningRow.Index, DataGridViewElementStates.Visible); int actualDisplayIndex = Owner.DataGridView.Rows.GetRowCount(DataGridViewElementStates.Visible, 0, previousVisibleRow); if (Owner.DataGridView.ColumnHeadersVisible) { // Add 1 because the first child in the data grid view acc obj is the top row header acc obj actualDisplayIndex++; } return Owner.DataGridView.AccessibilityObject.GetChild(actualDisplayIndex)?.GetChild(0); } } case AccessibleNavigation.Previous: default: return null; } } public override void Select(AccessibleSelection flags) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner is not DataGridViewRowHeaderCell dataGridViewCell) { return; } DataGridView? dataGridView = dataGridViewCell.DataGridView; if (dataGridView?.IsHandleCreated != true) { return; } if ((flags & AccessibleSelection.TakeFocus) == AccessibleSelection.TakeFocus) { dataGridView.Focus(); } if (dataGridViewCell.OwningRow is not null && (dataGridView.SelectionMode == DataGridViewSelectionMode.FullRowSelect || dataGridView.SelectionMode == DataGridViewSelectionMode.RowHeaderSelect)) { if ((flags & (AccessibleSelection.TakeSelection | AccessibleSelection.AddSelection)) != 0) { dataGridViewCell.OwningRow.Selected = true; } else if ((flags & AccessibleSelection.RemoveSelection) == AccessibleSelection.RemoveSelection) { dataGridViewCell.OwningRow.Selected = false; } } } #region IRawElementProviderFragment Implementation internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.OwningRow is null) { return null; } return direction switch { NavigateDirection.NavigateDirection_Parent => Owner.OwningRow.AccessibilityObject, NavigateDirection.NavigateDirection_NextSibling => (Owner.DataGridView is not null && Owner.DataGridView.Columns.GetColumnCount(DataGridViewElementStates.Visible) > 0) ? Owner.OwningRow.AccessibilityObject.GetChild(1) // go to the next sibling : null, _ => null, }; } #endregion #region IRawElementProviderSimple Implementation internal override VARIANT GetPropertyValue(UIA_PROPERTY_ID propertyId) => propertyId switch { UIA_PROPERTY_ID.UIA_ControlTypePropertyId => (VARIANT)(int)UIA_CONTROLTYPE_ID.UIA_HeaderControlTypeId, UIA_PROPERTY_ID.UIA_HasKeyboardFocusPropertyId => VARIANT.False, UIA_PROPERTY_ID.UIA_IsEnabledPropertyId => (VARIANT)(Owner?.DataGridView?.Enabled ?? false), UIA_PROPERTY_ID.UIA_IsKeyboardFocusablePropertyId => (VARIANT)State.HasFlag(AccessibleStates.Focusable), _ => base.GetPropertyValue(propertyId), }; #endregion } }