diff options
author | Samantha Houts <samantha@teamredwall.com> | 2017-01-31 11:49:15 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-31 11:49:15 -0800 |
commit | ae59382c9046501edb37882ad1c065aacce60319 (patch) | |
tree | 3578ce8e0396a38aeb8323d4051f50a19a5340fb /Xamarin.Forms.Platform.WinRT | |
parent | 23d228039acc504049f6a5153f5839d4c714930a (diff) | |
download | xamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.tar.gz xamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.tar.bz2 xamarin-forms-ae59382c9046501edb37882ad1c065aacce60319.zip |
[All] Basic Accessibility Support (#713)
* [Core] Add accessibility properties
* [Controls] Add accessibility gallery
* [iOS] Implement accessibility properties
* [Android] Implement accessibilty properties
* [Win] Implement accessibility properties
* [Win] Select ListView item on selected for a11y
* Update docs
* TODO: macOS accessibility
* [iOS] Fix failing UI Tests
Diffstat (limited to 'Xamarin.Forms.Platform.WinRT')
7 files changed, 220 insertions, 15 deletions
diff --git a/Xamarin.Forms.Platform.WinRT/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.WinRT/CarouselPageRenderer.cs index 11f4e09d..33e09399 100644 --- a/Xamarin.Forms.Platform.WinRT/CarouselPageRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/CarouselPageRenderer.cs @@ -70,6 +70,11 @@ namespace Xamarin.Forms.Platform.WinRT return new SizeRequest(result); } + UIElement IVisualElementRenderer.GetNativeElement() + { + return null; + } + public void SetElement(VisualElement element) { var newPage = element as CarouselPage; diff --git a/Xamarin.Forms.Platform.WinRT/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.WinRT/IVisualElementRenderer.cs index 4db9c1a6..abae812e 100644 --- a/Xamarin.Forms.Platform.WinRT/IVisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/IVisualElementRenderer.cs @@ -18,6 +18,9 @@ namespace Xamarin.Forms.Platform.WinRT event EventHandler<VisualElementChangedEventArgs> ElementChanged; SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint); + void SetElement(VisualElement element); + + UIElement GetNativeElement(); } }
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs b/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs index db581d52..031e2cf3 100644 --- a/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/ListViewRenderer.cs @@ -77,9 +77,6 @@ namespace Xamarin.Forms.Platform.WinRT // and prevented from bubbling up) rather than ListView.ItemClick List.Tapped += ListOnTapped; - // We also want to watch for the Enter key being pressed for selection - List.KeyUp += OnKeyPressed; - List.SelectionChanged += OnControlSelectionChanged; List.SetBinding(ItemsControl.ItemsSourceProperty, ""); @@ -141,7 +138,6 @@ namespace Xamarin.Forms.Platform.WinRT if (List != null) { List.Tapped -= ListOnTapped; - List.KeyUp -= OnKeyPressed; List.SelectionChanged -= OnControlSelectionChanged; @@ -508,17 +504,6 @@ namespace Xamarin.Forms.Platform.WinRT #endif } - void OnKeyPressed(object sender, KeyRoutedEventArgs e) - { - if (e.Key == VirtualKey.Enter) - { - if (Element.SelectedItem != null && Element.SelectedItem != List.SelectedItem) - { - ((IElementController)Element).SetValueFromRenderer(ListView.SelectedItemProperty, List.SelectedItem); - } - } - } - void OnControlSelectionChanged(object sender, SelectionChangedEventArgs e) { RestorePreviousSelectedVisual(); @@ -540,6 +525,10 @@ namespace Xamarin.Forms.Platform.WinRT } } #endif + + // A11y: Tapped event will not be routed when Narrator is active + // Also handles keyboard selection + SelectElementItem(); } FrameworkElement FindElement(object cell) @@ -553,6 +542,15 @@ namespace Xamarin.Forms.Platform.WinRT return null; } + void SelectElementItem() + { + if (List.SelectedItem != null && Element.SelectedItem != List.SelectedItem) + { + ((IElementController)Element).SetValueFromRenderer(ListView.SelectedItemProperty, List?.SelectedItem); + OnElementItemSelected(null, new SelectedItemChangedEventArgs(Element?.SelectedItem)); + } + } + #if WINDOWS_UWP void RestorePreviousSelectedVisual() { diff --git a/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs index 414870cd..dcef680e 100644 --- a/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/MasterDetailPageRenderer.cs @@ -94,6 +94,11 @@ namespace Xamarin.Forms.Platform.WinRT public event EventHandler<VisualElementChangedEventArgs> ElementChanged; + UIElement IVisualElementRenderer.GetNativeElement() + { + return null; + } + public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) { return new SizeRequest(new Size(Device.Info.ScaledScreenSize.Width, Device.Info.ScaledScreenSize.Height)); diff --git a/Xamarin.Forms.Platform.WinRT/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.WinRT/NavigationPageRenderer.cs index e8e3da41..185737aa 100644 --- a/Xamarin.Forms.Platform.WinRT/NavigationPageRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/NavigationPageRenderer.cs @@ -137,6 +137,11 @@ namespace Xamarin.Forms.Platform.WinRT return new SizeRequest(result); } + UIElement IVisualElementRenderer.GetNativeElement() + { + return null; + } + public void SetElement(VisualElement element) { if (element != null && !(element is NavigationPage)) diff --git a/Xamarin.Forms.Platform.WinRT/ViewRenderer.cs b/Xamarin.Forms.Platform.WinRT/ViewRenderer.cs index 148da1b3..0017531f 100644 --- a/Xamarin.Forms.Platform.WinRT/ViewRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/ViewRenderer.cs @@ -1,5 +1,6 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; #if WINDOWS_UWP @@ -11,6 +12,11 @@ namespace Xamarin.Forms.Platform.WinRT { public class ViewRenderer<TElement, TNativeElement> : VisualElementRenderer<TElement, TNativeElement> where TElement : View where TNativeElement : FrameworkElement { + string _defaultAutomationPropertiesName; + AccessibilityView? _defaultAutomationPropertiesAccessibilityView; + string _defaultAutomationPropertiesHelpText; + UIElement _defaultAutomationPropertiesLabeledBy; + protected override void OnElementChanged(ElementChangedEventArgs<TElement> e) { base.OnElementChanged(e); @@ -33,5 +39,97 @@ namespace Xamarin.Forms.Platform.WinRT Control.SetValue(AutomationProperties.AutomationIdProperty, id); } } + protected override void SetAutomationPropertiesName() + { + if (Control == null) + { + base.SetAutomationPropertiesName(); + return; + } + + if (Element == null) + return; + + if (_defaultAutomationPropertiesName == null) + _defaultAutomationPropertiesName = (string)Control.GetValue(AutomationProperties.NameProperty); + + var elemValue = (string)Element.GetValue(Accessibility.NameProperty); + + if (!string.IsNullOrWhiteSpace(elemValue)) + Control.SetValue(AutomationProperties.NameProperty, elemValue); + else + Control.SetValue(AutomationProperties.NameProperty, _defaultAutomationPropertiesName); + } + + protected override void SetAutomationPropertiesAccessibilityView() + { + if (Control == null) + { + base.SetAutomationPropertiesAccessibilityView(); + return; + } + + if (Element == null) + return; + + if (!_defaultAutomationPropertiesAccessibilityView.HasValue) + _defaultAutomationPropertiesAccessibilityView = (AccessibilityView)Control.GetValue(AutomationProperties.AccessibilityViewProperty); + + var newValue = _defaultAutomationPropertiesAccessibilityView; + var elemValue = (bool?)Element.GetValue(Accessibility.IsInAccessibleTreeProperty); + + if (elemValue == true) + newValue = AccessibilityView.Content; + else if (elemValue == false) + newValue = AccessibilityView.Raw; + + Control.SetValue(AutomationProperties.AccessibilityViewProperty, newValue); + } + + protected override void SetAutomationPropertiesHelpText() + { + if (Control == null) + { + base.SetAutomationPropertiesHelpText(); + return; + } + + if (Element == null) + return; + + if (_defaultAutomationPropertiesHelpText == null) + _defaultAutomationPropertiesHelpText = (string)Control.GetValue(AutomationProperties.HelpTextProperty); + + var elemValue = (string)Element.GetValue(Accessibility.HintProperty); + + if (!string.IsNullOrWhiteSpace(elemValue)) + Control.SetValue(AutomationProperties.HelpTextProperty, elemValue); + else + Control.SetValue(AutomationProperties.HelpTextProperty, _defaultAutomationPropertiesHelpText); + } + + protected override void SetAutomationPropertiesLabeledBy() + { + if (Control == null) + { + base.SetAutomationPropertiesLabeledBy(); + return; + } + + if (Element == null) + return; + + if (_defaultAutomationPropertiesLabeledBy == null) + _defaultAutomationPropertiesLabeledBy = (UIElement)Control.GetValue(AutomationProperties.LabeledByProperty); + + var elemValue = (VisualElement)Element.GetValue(Accessibility.LabeledByProperty); + var renderer = elemValue?.GetOrCreateRenderer(); + var nativeElement = renderer?.GetNativeElement(); + + if (nativeElement != null) + Control.SetValue(AutomationProperties.LabeledByProperty, nativeElement); + else + Control.SetValue(AutomationProperties.LabeledByProperty, _defaultAutomationPropertiesLabeledBy); + } } }
\ No newline at end of file diff --git a/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs b/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs index b81f73e3..402d1da8 100644 --- a/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/VisualElementRenderer.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Controls; #if WINDOWS_UWP @@ -17,6 +18,10 @@ namespace Xamarin.Forms.Platform.WinRT public class VisualElementRenderer<TElement, TNativeElement> : Panel, IVisualElementRenderer, IDisposable, IEffectControlProvider where TElement : VisualElement where TNativeElement : FrameworkElement { + string _defaultAutomationPropertiesName; + AccessibilityView? _defaultAutomationPropertiesAccessibilityView; + string _defaultAutomationPropertiesHelpText; + UIElement _defaultAutomationPropertiesLabeledBy; bool _disposed; EventHandler<VisualElementChangedEventArgs> _elementChangedHandlers; VisualElementTracker<TElement, TNativeElement> _tracker; @@ -108,6 +113,11 @@ namespace Xamarin.Forms.Platform.WinRT return new SizeRequest(result); } + public UIElement GetNativeElement() + { + return Control; + } + public void SetElement(VisualElement element) { TElement oldElement = Element; @@ -287,6 +297,14 @@ namespace Xamarin.Forms.Platform.WinRT UpdateEnabled(); else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) UpdateBackgroundColor(); + else if (e.PropertyName == Accessibility.HintProperty.PropertyName) + SetAutomationPropertiesHelpText(); + else if (e.PropertyName == Accessibility.NameProperty.PropertyName) + SetAutomationPropertiesName(); + else if (e.PropertyName == Accessibility.IsInAccessibleTreeProperty.PropertyName) + SetAutomationPropertiesAccessibilityView(); + else if (e.PropertyName == Accessibility.LabeledByProperty.PropertyName) + SetAutomationPropertiesLabeledBy(); } protected virtual void OnRegisterEffect(PlatformEffect effect) @@ -300,6 +318,75 @@ namespace Xamarin.Forms.Platform.WinRT SetValue(AutomationProperties.AutomationIdProperty, id); } + protected virtual void SetAutomationPropertiesName() + { + if (Element == null || Control == null) + return; + + if (_defaultAutomationPropertiesName == null) + _defaultAutomationPropertiesName = (string)Control.GetValue(AutomationProperties.NameProperty); + + var elemValue = (string)Element.GetValue(Accessibility.NameProperty); + + if (!string.IsNullOrWhiteSpace(elemValue)) + Control.SetValue(AutomationProperties.NameProperty, elemValue); + else + Control.SetValue(AutomationProperties.NameProperty, _defaultAutomationPropertiesName); + } + + protected virtual void SetAutomationPropertiesAccessibilityView() + { + if (Element == null || Control == null) + return; + + if (!_defaultAutomationPropertiesAccessibilityView.HasValue) + _defaultAutomationPropertiesAccessibilityView = (AccessibilityView)Control.GetValue(AutomationProperties.AccessibilityViewProperty); + + var newValue = _defaultAutomationPropertiesAccessibilityView; + var elemValue = (bool?)Element.GetValue(Accessibility.IsInAccessibleTreeProperty); + + if (elemValue == true) + newValue = AccessibilityView.Content; + else if (elemValue == false) + newValue = AccessibilityView.Raw; + + Control.SetValue(AutomationProperties.AccessibilityViewProperty, newValue); + } + + protected virtual void SetAutomationPropertiesHelpText() + { + if (Element == null || Control == null) + return; + + if (_defaultAutomationPropertiesHelpText == null) + _defaultAutomationPropertiesHelpText = (string)Control.GetValue(AutomationProperties.HelpTextProperty); + + var elemValue = (string)Element.GetValue(Accessibility.HintProperty); + + if (!string.IsNullOrWhiteSpace(elemValue)) + Control.SetValue(AutomationProperties.HelpTextProperty, elemValue); + else + Control.SetValue(AutomationProperties.HelpTextProperty, _defaultAutomationPropertiesHelpText); + } + + protected virtual void SetAutomationPropertiesLabeledBy() + { + if (Element == null || Control == null) + return; + + if (_defaultAutomationPropertiesLabeledBy == null) + _defaultAutomationPropertiesLabeledBy = (UIElement)Control.GetValue(AutomationProperties.LabeledByProperty); + + var elemValue = (VisualElement)Element.GetValue(Accessibility.LabeledByProperty); + var renderer = elemValue?.GetOrCreateRenderer(); + var nativeElement = renderer?.GetNativeElement(); + + if (nativeElement != null) + Control.SetValue(AutomationProperties.LabeledByProperty, nativeElement); + else + Control.SetValue(AutomationProperties.LabeledByProperty, _defaultAutomationPropertiesLabeledBy); + } + protected void SetNativeControl(TNativeElement control) { TNativeElement oldControl = Control; @@ -367,6 +454,10 @@ namespace Xamarin.Forms.Platform.WinRT protected virtual void UpdateNativeControl() { UpdateEnabled(); + SetAutomationPropertiesHelpText(); + SetAutomationPropertiesName(); + SetAutomationPropertiesAccessibilityView(); + SetAutomationPropertiesLabeledBy(); } internal virtual void OnElementFocusChangeRequested(object sender, VisualElement.FocusRequestArgs args) |