// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.Drawing; using Windows.Win32.System.Variant; using Windows.Win32.UI.Accessibility; namespace System.Windows.Forms; public partial class DataGridViewColumnHeaderCell { protected class DataGridViewColumnHeaderCellAccessibleObject : DataGridViewCellAccessibleObject { public DataGridViewColumnHeaderCellAccessibleObject(DataGridViewColumnHeaderCell? owner) : base(owner) { } /// <summary> /// Returns the index of a column, taking into account DisplayIndex properties /// and the invisibility of other columns /// </summary> private int VisibleIndex => Owner?.DataGridView is not null && Owner.OwningColumn is not null ? Owner.DataGridView.RowHeadersVisible ? Owner.DataGridView.Columns.GetVisibleIndex(Owner.OwningColumn) + 1 : Owner.DataGridView.Columns.GetVisibleIndex(Owner.OwningColumn) : -1; public override Rectangle Bounds => Owner is null ? throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet) : (Owner.DataGridView?.IsHandleCreated == true) ? GetAccessibleObjectBounds(Parent) : Rectangle.Empty; public override string DefaultAction { get { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.OwningColumn is not null) { if (Owner.OwningColumn.SortMode == DataGridViewColumnSortMode.Automatic) { return SR.DataGridView_AccColumnHeaderCellDefaultAction; } else if (Owner.DataGridView is not null && ( Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.FullColumnSelect || Owner.DataGridView.SelectionMode == DataGridViewSelectionMode.ColumnHeaderSelect)) { return SR.DataGridView_AccColumnHeaderCellSelectDefaultAction; } } return string.Empty; } } public override string Name => Owner is null ? throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet) : Owner.OwningColumn?.HeaderText ?? string.Empty; // return the top header row accessible object public override AccessibleObject? Parent => Owner is null ? throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet) : Owner.DataGridView?.AccessibilityObject.GetChild(0); public override AccessibleRole Role => AccessibleRole.ColumnHeader; 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.OwningColumn is not null && Owner.OwningColumn.Selected) { if (Owner.DataGridView.SelectionMode is DataGridViewSelectionMode.FullColumnSelect or DataGridViewSelectionMode.ColumnHeaderSelect) { resultState |= AccessibleStates.Selected; } } return resultState; } } public override string Value => Name; public override void DoDefaultAction() { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner is not DataGridViewColumnHeaderCell dataGridViewCell) { return; } DataGridView? dataGridView = dataGridViewCell.DataGridView; if (dataGridView?.IsHandleCreated != true || dataGridViewCell.OwningColumn is null) { return; } if (dataGridViewCell.OwningColumn.SortMode == DataGridViewColumnSortMode.Automatic) { ListSortDirection listSortDirection = dataGridView.SortedColumn == dataGridViewCell.OwningColumn && dataGridView.SortOrder == SortOrder.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; dataGridView.Sort(dataGridViewCell.OwningColumn, listSortDirection); } else if (dataGridView.SelectionMode is DataGridViewSelectionMode.FullColumnSelect or DataGridViewSelectionMode.ColumnHeaderSelect) { dataGridViewCell.OwningColumn.Selected = true; } } public override AccessibleObject? Navigate(AccessibleNavigation navigationDirection) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner.OwningColumn is null || Owner.DataGridView is null) { return null; } return navigationDirection switch { AccessibleNavigation.Right => Owner.DataGridView.RightToLeft == RightToLeft.No ? NavigateForward() : NavigateBackward(), AccessibleNavigation.Next => NavigateForward(), AccessibleNavigation.Left => Owner.DataGridView.RightToLeft == RightToLeft.No ? NavigateBackward() : NavigateForward(), AccessibleNavigation.Previous => NavigateBackward(), _ => null, }; } private AccessibleObject? NavigateBackward() { Debug.Assert(Owner is not null); // This method is called after _owner and its properties are validated if (Owner.OwningColumn is null || Owner.DataGridView is null) { return null; } if (Owner.OwningColumn == Owner.DataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible)) { // return the row header cell accessible object for the current row if Owner.DataGridView.RowHeadersVisible == false return Owner.DataGridView.RowHeadersVisible ? Parent?.GetChild(0) : null; } else { // Subtract 1 because the top header row accessible object has the top left header cell accessible object at the beginning return Parent?.GetChild(VisibleIndex - 1); } } private AccessibleObject? NavigateForward() { Debug.Assert(Owner is not null); // This method is called after _owner and its properties are validated if (Owner.OwningColumn is null || Owner.DataGridView is null || Owner.OwningColumn == Owner.DataGridView.Columns.GetLastColumn(DataGridViewElementStates.Visible, DataGridViewElementStates.None)) { return null; } // Add 1 because the top header row accessible object has the top left header cell accessible object at the beginning int visibleIndex = VisibleIndex; return visibleIndex < 0 ? null : Parent?.GetChild(visibleIndex + 1); } public override void Select(AccessibleSelection flags) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } if (Owner is not DataGridViewColumnHeaderCell dataGridViewCell) { return; } DataGridView? dataGridView = dataGridViewCell.DataGridView; if (dataGridView?.IsHandleCreated != true) { return; } if ((flags & AccessibleSelection.TakeFocus) == AccessibleSelection.TakeFocus) { dataGridView.Focus(); } if (dataGridViewCell.OwningColumn is not null && (dataGridView.SelectionMode == DataGridViewSelectionMode.FullColumnSelect || dataGridView.SelectionMode == DataGridViewSelectionMode.ColumnHeaderSelect)) { if ((flags & (AccessibleSelection.TakeSelection | AccessibleSelection.AddSelection)) != 0) { dataGridViewCell.OwningColumn.Selected = true; } else if ((flags & AccessibleSelection.RemoveSelection) == AccessibleSelection.RemoveSelection) { dataGridViewCell.OwningColumn.Selected = false; } } } #region IRawElementProviderFragment Implementation internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) { if (Owner is null) { throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet); } return direction switch { NavigateDirection.NavigateDirection_Parent => Parent, NavigateDirection.NavigateDirection_NextSibling => NavigateForward(), NavigateDirection.NavigateDirection_PreviousSibling => NavigateBackward(), _ => null }; } #endregion #region IRawElementProviderSimple Implementation internal override bool IsPatternSupported(UIA_PATTERN_ID patternId) => patternId.Equals(UIA_PATTERN_ID.UIA_LegacyIAccessiblePatternId) || patternId.Equals(UIA_PATTERN_ID.UIA_InvokePatternId); 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), UIA_PROPERTY_ID.UIA_IsPasswordPropertyId => VARIANT.False, _ => base.GetPropertyValue(propertyId) }; #endregion } } |