| File: System\Windows\Forms\Controls\TabControl\TabPage.TabAccessibleObject.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// 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 TabPage { internal class TabAccessibleObject : AccessibleObject { private readonly TabPage _owningTabPage; public TabAccessibleObject(TabPage owningTabPage) { _owningTabPage = owningTabPage.OrThrowIfNull(); } private protected override string AutomationId => _owningTabPage.Name; public override Rectangle Bounds { get { if (OwningTabControl is null || !OwningTabControl.IsHandleCreated || SystemIAccessibleInternal is null) { return Rectangle.Empty; } int index = CurrentIndex; if (index == -1 || (State & AccessibleStates.Invisible) == AccessibleStates.Invisible) { return Rectangle.Empty; } // The "GetChildId" method returns to the id of the TabControl element, // which allows to use the native "accLocation" method to get the "Bounds" property return SystemIAccessibleInternal.TryGetLocation(GetChildId()); } } public override string? DefaultAction => GetDefaultActionInternal().ToNullableStringAndFree(); private protected override bool IsInternal => true; internal override BSTR GetDefaultActionInternal() => SystemIAccessibleInternal.TryGetDefaultAction(GetChildId()); public override string? Name => _owningTabPage.Text; internal override bool CanGetNameInternal => false; private TabControl? OwningTabControl => _owningTabPage.ParentInternal as TabControl; public override AccessibleRole Role => SystemIAccessibleInternal.TryGetRole(GetChildId()); public override AccessibleStates State => SystemIAccessibleInternal.TryGetState(GetChildId()); internal override IRawElementProviderFragmentRoot.Interface? FragmentRoot => OwningTabControl?.AccessibilityObject; internal override bool IsItemSelected => OwningTabControl?.SelectedTab == _owningTabPage; internal override IRawElementProviderSimple.Interface? ItemSelectionContainer => OwningTabControl?.AccessibilityObject; internal override int[] RuntimeId => [ RuntimeIDFirstItem, OwningTabControl is null ? (int)IntPtr.Zero : (int)OwningTabControl.InternalHandle, GetHashCode() ]; private int CurrentIndex => OwningTabControl?.TabPages.IndexOf(_owningTabPage) ?? -1; private AgileComPointer<IAccessible>? SystemIAccessibleInternal => OwningTabControl?.AccessibilityObject.SystemIAccessible; public override void DoDefaultAction() { if (OwningTabControl is not null && OwningTabControl.IsHandleCreated && OwningTabControl.Enabled) { OwningTabControl.SelectedTab = _owningTabPage; } } internal override void AddToSelection() => DoDefaultAction(); internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) { if (OwningTabControl is null || !OwningTabControl.IsHandleCreated) { return null; } return direction switch { NavigateDirection.NavigateDirection_Parent => OwningTabControl.AccessibilityObject, NavigateDirection.NavigateDirection_NextSibling => OwningTabControl.AccessibilityObject.GetChild(GetChildId() + 1), NavigateDirection.NavigateDirection_PreviousSibling => OwningTabControl.AccessibilityObject.GetChild(GetChildId() - 1), _ => null }; } // +1 is needed because 0 is the Pane id of the selected tab internal override int GetChildId() => CurrentIndex + 1; public override string? Help => GetHelpInternal().ToNullableStringAndFree(); internal override BSTR GetHelpInternal() => SystemIAccessibleInternal.TryGetHelp(GetChildId()); public override string? KeyboardShortcut => GetKeyboardShortcutInternal((VARIANT)GetChildId()).ToNullableStringAndFree(); internal override BSTR GetKeyboardShortcutInternal(VARIANT childID) => SystemIAccessibleInternal.TryGetKeyboardShortcut(childID); internal override VARIANT GetPropertyValue(UIA_PROPERTY_ID propertyID) => propertyID switch { UIA_PROPERTY_ID.UIA_ControlTypePropertyId => (VARIANT)(int)UIA_CONTROLTYPE_ID.UIA_TabItemControlTypeId, UIA_PROPERTY_ID.UIA_HasKeyboardFocusPropertyId => (VARIANT)State.HasFlag(AccessibleStates.Focused), UIA_PROPERTY_ID.UIA_IsEnabledPropertyId => (VARIANT)(OwningTabControl?.Enabled ?? false), UIA_PROPERTY_ID.UIA_IsKeyboardFocusablePropertyId // This is necessary for compatibility with MSAA proxy: // IsKeyboardFocusable = true regardless the control is enabled/disabled. => VARIANT.True, _ => base.GetPropertyValue(propertyID) }; internal override bool IsPatternSupported(UIA_PATTERN_ID patternId) => patternId switch { // The "Enabled" property of the TabControl does not affect the behavior of that property, // so it is always true UIA_PATTERN_ID.UIA_SelectionItemPatternId => true, UIA_PATTERN_ID.UIA_InvokePatternId => false, UIA_PATTERN_ID.UIA_LegacyIAccessiblePatternId => true, _ => base.IsPatternSupported(patternId) }; internal override void RemoveFromSelection() { // Do nothing, C++ implementation returns UIA_E_INVALIDOPERATION 0x80131509 } internal override unsafe void SelectItem() => DoDefaultAction(); } }