| File: System\Windows\Forms\Controls\ComboBox\ComboBox.ComboBoxItemAccessibleObject.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.Com; using Windows.Win32.System.Variant; using Windows.Win32.UI.Accessibility; using static System.Windows.Forms.ComboBox.ObjectCollection; namespace System.Windows.Forms; public partial class ComboBox { /// <summary> /// Represents the <see cref="ComboBox"/> item accessible object. /// </summary> internal sealed class ComboBoxItemAccessibleObject : AccessibleObject { private readonly ComboBox _owningComboBox; private readonly Entry _owningItem; /// <summary> /// Initializes new instance of <see cref="ComboBox"/> item accessible object. /// </summary> /// <param name="owningComboBox">The owning <see cref="ComboBox"/>.</param> /// <param name="owningItem">The owning <see cref="ComboBox"/> item.</param> public ComboBoxItemAccessibleObject(ComboBox owningComboBox, Entry owningItem) { _owningComboBox = owningComboBox.OrThrowIfNull(); _owningItem = owningItem; } public override Rectangle Bounds { get { int currentIndex = GetCurrentIndex(); var listHandle = _owningComboBox.GetListHandle(); RECT itemRect = default; int result = (int)PInvokeCore.SendMessage( listHandle, PInvoke.LB_GETITEMRECT, (WPARAM)currentIndex, ref itemRect); if (result == PInvoke.LB_ERR) { return Rectangle.Empty; } // Translate the item rect to screen coordinates RECT translated = itemRect; PInvokeCore.MapWindowPoints(listHandle, HWND.Null, ref translated); return translated; } } public override string? DefaultAction => GetDefaultActionInternal().ToNullableStringAndFree(); internal override BSTR GetDefaultActionInternal() => _owningComboBox.ChildListAccessibleObject.SystemIAccessible.TryGetDefaultAction(GetChildId()); private protected override bool IsInternal => true; internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) { if (direction == NavigateDirection.NavigateDirection_Parent) { return _owningComboBox.ChildListAccessibleObject; } if (_owningComboBox.ChildListAccessibleObject is not ComboBoxChildListUiaProvider comboBoxChildListUiaProvider) { return base.FragmentNavigate(direction); } switch (direction) { case NavigateDirection.NavigateDirection_NextSibling: int currentIndex = GetCurrentIndex(); int itemsCount = comboBoxChildListUiaProvider.GetChildFragmentCount(); int nextItemIndex = currentIndex + 1; if (itemsCount > nextItemIndex) { return comboBoxChildListUiaProvider.GetChildFragment(nextItemIndex); } break; case NavigateDirection.NavigateDirection_PreviousSibling: currentIndex = GetCurrentIndex(); int previousItemIndex = currentIndex - 1; if (previousItemIndex >= 0) { return comboBoxChildListUiaProvider.GetChildFragment(previousItemIndex); } break; } return base.FragmentNavigate(direction); } internal override IRawElementProviderFragmentRoot.Interface FragmentRoot => _owningComboBox.AccessibilityObject; private int GetCurrentIndex() => _owningComboBox.Items.InnerList.IndexOf(_owningItem); // Index is zero-based, Child ID is 1-based. internal override int GetChildId() => GetCurrentIndex() + 1; internal override unsafe VARIANT GetPropertyValue(UIA_PROPERTY_ID propertyID) => propertyID switch { UIA_PROPERTY_ID.UIA_ControlTypePropertyId => (VARIANT)(int)UIA_CONTROLTYPE_ID.UIA_ListItemControlTypeId, UIA_PROPERTY_ID.UIA_HasKeyboardFocusPropertyId => (VARIANT)(_owningComboBox.Focused && _owningComboBox.SelectedIndex == GetCurrentIndex()), UIA_PROPERTY_ID.UIA_IsContentElementPropertyId => VARIANT.True, UIA_PROPERTY_ID.UIA_IsControlElementPropertyId => VARIANT.True, UIA_PROPERTY_ID.UIA_IsEnabledPropertyId => (VARIANT)_owningComboBox.Enabled, UIA_PROPERTY_ID.UIA_IsKeyboardFocusablePropertyId => (VARIANT)State.HasFlag(AccessibleStates.Focusable), UIA_PROPERTY_ID.UIA_SelectionItemIsSelectedPropertyId => (VARIANT)State.HasFlag(AccessibleStates.Selected), UIA_PROPERTY_ID.UIA_SelectionItemSelectionContainerPropertyId => (VARIANT)ComHelpers.GetComPointer<IUnknown>(_owningComboBox.ChildListAccessibleObject), _ => base.GetPropertyValue(propertyID) }; public override string? Help => GetHelpInternal().ToNullableStringAndFree(); internal override BSTR GetHelpInternal() => _owningComboBox.ChildListAccessibleObject.SystemIAccessible.TryGetHelp(GetChildId()); internal override bool IsPatternSupported(UIA_PATTERN_ID patternId) { return patternId switch { UIA_PATTERN_ID.UIA_LegacyIAccessiblePatternId or UIA_PATTERN_ID.UIA_InvokePatternId or UIA_PATTERN_ID.UIA_ScrollItemPatternId or UIA_PATTERN_ID.UIA_SelectionItemPatternId => true, _ => base.IsPatternSupported(patternId), }; } public override string? Name => _owningComboBox is null ? base.Name : _owningComboBox.GetItemText(_owningItem.Item); internal override bool CanGetNameInternal => _owningComboBox is null; public override AccessibleRole Role => _owningComboBox.ChildListAccessibleObject.SystemIAccessible.TryGetRole(GetChildId()); internal override int[] RuntimeId => [ RuntimeIDFirstItem, (int)_owningComboBox.InternalHandle, _owningComboBox.GetListNativeWindowRuntimeIdPart(), _owningItem.GetHashCode() ]; public override AccessibleStates State { get { AccessibleStates state = _owningComboBox.ChildListAccessibleObject.SystemIAccessible.TryGetState(GetChildId()); if (!_owningComboBox.DroppedDown || !_owningComboBox.ChildListAccessibleObject.Bounds.IntersectsWith(Bounds)) { state |= AccessibleStates.Offscreen; } return state; } } internal override void ScrollIntoView() { if (!_owningComboBox.IsHandleCreated || !_owningComboBox.Enabled) { return; } Rectangle listBounds = _owningComboBox.ChildListAccessibleObject.Bounds; if (listBounds.IntersectsWith(Bounds)) { // Do nothing because the item is already visible return; } PInvokeCore.SendMessage(_owningComboBox, PInvoke.CB_SETTOPINDEX, (WPARAM)GetCurrentIndex()); } internal override void SetFocus() { RaiseAutomationEvent(UIA_EVENT_ID.UIA_AutomationFocusChangedEventId); base.SetFocus(); } internal override unsafe void SelectItem() { if (!_owningComboBox.IsHandleCreated) { return; } _owningComboBox.SelectedIndex = GetCurrentIndex(); PInvoke.InvalidateRect(_owningComboBox.GetListHandle(), lpRect: null, bErase: false); } internal override void AddToSelection() { if (!_owningComboBox.IsHandleCreated) { return; } SelectItem(); } internal override void RemoveFromSelection() { // Do nothing, C++ implementation returns UIA_E_INVALIDOPERATION 0x80131509 } internal override bool IsItemSelected => (State & AccessibleStates.Selected) != 0; internal override IRawElementProviderSimple.Interface ItemSelectionContainer => _owningComboBox.ChildListAccessibleObject; } }