private string GetSimpleAccessibilityName() { if (FeatureConfiguration.AutomationPeer.UseSimpleAccessibility && Owner is View view && AutomationProperties.GetAccessibilityView(Owner) != AccessibilityView.Raw) { /// We get our name by aggregating the name of all our children. /// See <see cref="FeatureConfiguration.AutomationPeer.UseSimpleAccessibility" /> for details. return(string.Join(", ", view .EnumerateAllChildren() .OfType <IFrameworkElement>() .Where(child => child.Visibility == Visibility.Visible) .Select(child => { // We set this for two reasons: // - We want to disable accessibility focus for elements whose names are aggregated into the name of their parent. // - We want to prevent these elements from enumerating their own children in GetSimpleAccessibilityName(), // which might be called as a result of calling automationPeer.GetName() below. AutomationProperties.SetAccessibilityView(child, AccessibilityView.Raw); return child; }) .Select(FromIFrameworkElement) .Where(automationPeer => automationPeer != null) .Select(automationPeer => automationPeer.GetName()) .Where(childName => !string.IsNullOrEmpty(childName)) )); }
/// <summary> /// Updates name on <paramref name="element"/> from <see cref="AccessibilityLabelAttachedProperty"/> /// or from generation, and then updates all parents' generated names where update is due. /// </summary> /// <param name="element"></param> private static void UpdateName(UIElement element) { // Update name on the element itself from AccessibilityLabel or name generation. var peer = FrameworkElementAutomationPeer.FromElement(element); if (IsInGenerativeState(element)) { if (AutomationProperties.GetAccessibilityView(element) != AccessibilityView.Raw) { var generatedName = GenerateNameFromUpdated(peer); AutomationProperties.SetName(element, generatedName); } } else { var accessibilityLabel = GetAccessibilityLabelAttached(element); if (string.IsNullOrEmpty(accessibilityLabel)) { element.ClearValue(AutomationProperties.NameProperty); } else { AutomationProperties.SetName(element, accessibilityLabel); } } // Update generated names only starting from parent and up. var parentPeer = peer.Navigate(AutomationNavigationDirection.Parent) as AutomationPeer; if (parentPeer != null) { UpdateGeneratedNameHereAndUp(parentPeer); } }
public ImplicitTextBlock(DependencyObject parent) { // Propagate the parent's (ContentPresenter or ContentControl) AutomationProperties.AccessibilityView to ImplicitTextBlock once. var accessibilityView = AutomationProperties.GetAccessibilityView(parent); AutomationProperties.SetAccessibilityView(this, accessibilityView); }
internal override void OnInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { if (!AutomationConfiguration.IsAccessibilityEnabled) { return; } var isAccessible = AutomationProperties.GetAccessibilityView(Owner) != AccessibilityView.Raw; if (isAccessible) { // TODO: Set View.Focusable and View.FocusableInTouchMode to true to ensure SendAccessibilityEvent gets called? info.Focusable = isAccessible; info.ContentDescription = GetName(); info.Password = IsPassword(); info.Enabled = IsEnabled(); // TODO: Use GetAutomationControlType() and GetPattern() instead info.Clickable = GetClickable(); info.Checked = GetChecked(); info.Checkable = GetCheckable(); info.Editable = GetEditable(); info.InputType = GetInputType(); info.MultiLine = GetMultiline(); info.Selected = GetSelected(); info.MaxTextLength = GetMaxTextLength(); info.Scrollable = GetScrollable(); } }
public void VerifyAccessibilityView() { RunOnUIThread.Execute(() => { var progressRing = new ProgressRing(); progressRing.IsActive = true; Verify.AreNotEqual(AccessibilityView.Raw, AutomationProperties.GetAccessibilityView(progressRing)); progressRing.IsActive = false; Verify.AreEqual(AccessibilityView.Raw, AutomationProperties.GetAccessibilityView(progressRing)); }); }
/// <summary> /// Update <see cref="AutomationProperties.NameProperty"/> on <paramref name="peer"/>'s owner /// and all its parents as far up as needed and only when the name is generated. This must be called /// when anything influencing generated names has changed in <paramref name="peer"/>'s owner or somewhere in its subtree. /// </summary> /// <param name="peer"></param> private static void UpdateGeneratedNameHereAndUp(AutomationPeer peer) { var current = peer; while (current != null) { UIElement element = GetUIElementFromAutomationPeer(current); if (IsElementIgnoresChildrenForName(element)) { break; } if (IsInGenerativeState(element) && (AutomationProperties.GetAccessibilityView(element) != AccessibilityView.Raw)) { var generatedName = GenerateNameFromUpdated(current); AutomationProperties.SetName(element, generatedName); } current = current.Navigate(AutomationNavigationDirection.Parent) as AutomationPeer; } }
internal override bool UpdateAccessibilityElement() { if (!AutomationConfiguration.IsAccessibilityEnabled) { return(false); } var isAccessible = AutomationProperties.GetAccessibilityView(Owner) != AccessibilityView.Raw; if (isAccessible && Owner is UIView view) { view.AccessibilityLabel = GetName(); view.AccessibilityTraits = GetAccessibilityTraits(); // TODO //view.AccessibilityHint //view.AccessibilityValue //view.AccessibilityElementsHidden //view.AccessibilityNavigationStyle } return(isAccessible); }
/// <summary> /// Sets AccessibilityView property for <paramref name="element"/> and its children according to /// the element's <paramref name="importantForAccessibility"/> property and /// <see cref="AccessibilityLabelAttachedProperty"/> values. /// </summary> /// <param name="element"></param> /// <param name="elementPeer"></param> /// <param name="importantForAccessibility"></param> private static void UpdateAccessibilityViewForUIElement(UIElement element, AutomationPeer elementPeer, ImportantForAccessibility importantForAccessibility) { switch (importantForAccessibility) { case ImportantForAccessibility.Auto when GetAccessibilityLabelAttached(element) == null: element.ClearValue(AutomationProperties.AccessibilityViewProperty); SetChildrenAccessibilityViewFromImportantForAccessibility(elementPeer); break; case ImportantForAccessibility.Auto when GetAccessibilityLabelAttached(element) != null: case ImportantForAccessibility.Yes: var currentAccessibilityView = AutomationProperties.GetAccessibilityView(element); AutomationProperties.SetAccessibilityView(element, AccessibilityView.Content); // Generate the label in case the element was hidden. if (currentAccessibilityView == AccessibilityView.Raw) { UpdateName(element); } SetChildrenAccessibilityView(elementPeer, AccessibilityView.Raw); break; case ImportantForAccessibility.No: AutomationProperties.SetAccessibilityView(element, AccessibilityView.Raw); SetChildrenAccessibilityViewFromImportantForAccessibility(elementPeer); break; case ImportantForAccessibility.NoHideDescendants: AutomationProperties.SetAccessibilityView(element, AccessibilityView.Raw); SetChildrenAccessibilityView(elementPeer, AccessibilityView.Raw); break; default: break; } }
/// <summary> /// True if the <paramref name="element"/> generates name, but it is not visible to narrator. /// </summary> /// <param name="element"></param> /// <returns></returns> private static bool IsInGenerativeStateAndHidden(UIElement element) => AutomationProperties.GetAccessibilityView(element) == AccessibilityView.Raw && IsInGenerativeState(element);
protected override bool IsControlElementCore() => AutomationProperties.GetAccessibilityView(Owner) >= AccessibilityView.Control;
public void ExpanderAutomationPeerTest() { RunOnUIThread.Execute(() => { var root = (StackPanel)XamlReader.Load( @"<StackPanel xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:primitives='using:Microsoft.UI.Xaml.Controls.Primitives' xmlns:controls='using:Microsoft.UI.Xaml.Controls'> <controls:Expander x:Name ='ExpandedExpander' AutomationProperties.Name='ExpandedExpander' IsExpanded='True' Margin='12' HorizontalAlignment='Left'> <controls:Expander.Header> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width='80'/> </Grid.ColumnDefinitions> <StackPanel Margin='0,14,0,16'> <TextBlock AutomationProperties.Name='test' Text='This expander is expanded by default.' Margin='0,0,0,4' /> <TextBlock Text='This is the second line of text.' /> </StackPanel> <ToggleSwitch Grid.Column='1'/> </Grid> </controls:Expander.Header> <Button AutomationProperties.AutomationId = 'ExpandedExpanderContent'> Content </Button> </controls:Expander> </StackPanel>"); Content = root; Content.UpdateLayout(); var expander = VisualTreeHelper.GetChild(root, 0) as Expander; expander.IsExpanded = true; Content.UpdateLayout(); var grid = VisualTreeHelper.GetChild(expander, 0); var toggleButton = VisualTreeHelper.GetChild(grid, 0); var toggleButtonGrid = VisualTreeHelper.GetChild(toggleButton, 0); var contentPresenter = VisualTreeHelper.GetChild(toggleButtonGrid, 0); var grid2 = VisualTreeHelper.GetChild(contentPresenter, 0); var stackPanel = VisualTreeHelper.GetChild(grid2, 0); var textBlock1 = VisualTreeHelper.GetChild(stackPanel, 0) as TextBlock; var textBlock2 = VisualTreeHelper.GetChild(stackPanel, 1) as TextBlock; var toggleSwitch = VisualTreeHelper.GetChild(grid2, 1) as ToggleSwitch; var border = VisualTreeHelper.GetChild(grid, 1); var expanderContentBorder = VisualTreeHelper.GetChild(border, 0); var expanderContentContentPresenter = VisualTreeHelper.GetChild(expanderContentBorder, 0); var button = VisualTreeHelper.GetChild(expanderContentContentPresenter, 0) as Button; Verify.AreEqual("ExpandedExpander", AutomationProperties.GetName(expander)); // Verify ExpandedExpander header content are included in the accessibility tree Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock1), AccessibilityView.Content); Verify.AreEqual(AutomationProperties.GetAccessibilityView(textBlock2), AccessibilityView.Content); Verify.AreEqual(AutomationProperties.GetAccessibilityView(toggleSwitch), AccessibilityView.Content); // Verify ExpandedExpander content is included in the accessibility tree Verify.AreEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Content); expander.IsExpanded = false; Content.UpdateLayout(); // Verify ExpandedExpander content is not included in the accessibility tree and not readable once collapsed Verify.AreNotEqual(AutomationProperties.GetAccessibilityView(button), AccessibilityView.Raw); }); }