ter*_*ory 3 win-universal-app uwp
我已经创建了一个UWP自定义(即模板化)控件.我如何使其可访问?
现在,当我尝试将它与Windows讲述人工具一起使用时,它的表现很差.有时讲述者根本看不到它,有时它会在我不想要的时候深入到我控制范围内的UI元素树中.
最初我认为我只需要设置一些自动附加属性,但它们没有明显的效果.
所以当我发现AutomationPeer对象时,我就有了这个.基本上每个控件类都需要一个关联的AutomationPeer类,它将特定控件的行为映射到可访问性工具要使用的一组标准.
为了简单起见,我创建了一个简单的AccessibleButton类,它直接从Control派生.(如果你真的在制作一个按钮,你可能想要从Button或ButtonBase派生,但是已经有了一个相关的AutomationPeer类.我只是为了解释的目的而努力.)
这是Generic.xaml代码:
<Style TargetType="local:AccessibleButton">
<Setter Property="UseSystemFocusVisuals" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AccessibleButton">
<Grid Background="{TemplateBinding Background}">
<Border BorderThickness="10">
<TextBlock x:Name="Name" Text="{TemplateBinding Label}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
这是背后的代码:
public sealed class AccessibleButton : Control
{
public AccessibleButton()
{
this.DefaultStyleKey = typeof(AccessibleButton);
}
public static DependencyProperty LabelProperty = DependencyProperty.Register(
"Label", typeof(string), typeof(AccessibleButton),
PropertyMetadata.Create(string.Empty));
public string Label
{
set { SetValue(LabelProperty, value); }
get { return (string)GetValue(LabelProperty); }
}
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
Click?.Invoke(this, EventArgs.Empty);
}
public event EventHandler Click;
}
Run Code Online (Sandbox Code Playgroud)
以及MainPage.xaml中的一些示例用法:
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:AccessibleButton Background="Red" Label="Click Me!" Click="AccessibleButton_Click"/>
<local:AccessibleButton Background="Green" Label="No, Click Me!" Click="AccessibleButton_Click"/>
<local:AccessibleButton Background="Blue" Label="Ignore them, Click Me!" Click="AccessibleButton_Click"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
如果你在每个按钮上运行讲述人和鼠标,你会发现它忽略了按钮的边框(你只是得到一点点击声).如果将鼠标悬停在文本上,它有时会读取整个文本,但通常会读取单个单词以及文本末尾的神秘"空行".我猜测TextBlock控件将其输入分解为每个单词的单个对象......
这很糟糕.
该修复程序是AutomationPeer.这是基础课:
public class AccessibleButtonAutomationPeer : FrameworkElementAutomationPeer
{
public AccessibleButtonAutomationPeer(FrameworkElement owner): base(owner)
{
}
}
Run Code Online (Sandbox Code Playgroud)
(FrameworkElementAutomationPeer位于Windows.UI.Xaml.Automation.Peers命名空间中.)
在AccessibleButton类中添加此覆盖以创建它:
protected override AutomationPeer OnCreateAutomationPeer()
{
return new AccessibleButtonAutomationPeer(this);
}
Run Code Online (Sandbox Code Playgroud)
这没什么用处.我们需要添加一些方法.首先,通过实现GetChildrenCore()方法,让屏幕阅读器无法看到我们按钮的内容:
protected override IList<AutomationPeer> GetChildrenCore()
{
return null;
}
Run Code Online (Sandbox Code Playgroud)
如果你只是这样跑,你会发现它现在没什么作用.如果一个控件确实得到了焦点,它只会说"自定义".我们可以通过实现GetNameCore()方法让它在控件标签中说出来:
protected override string GetNameCore()
{
return ((AccessibleButton)Owner).Label;
}
Run Code Online (Sandbox Code Playgroud)
这有帮助.现在,只要我们选择一个控件,它就会说出按钮标签文本.但它最后仍然说"自定义".要解决这个问题,我们必须通过实现GetAutomationControlTypeCore()方法来告诉系统它是什么类型的控件来指示控件是一个按钮:
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Button;
}
Run Code Online (Sandbox Code Playgroud)
现在它会说按钮标签后面跟着"按钮".
这实际上很有用!
视力不佳但能够通过鼠标或触摸导航屏幕的用户至少知道这些按钮上的标签是什么.
AutomationPeers还允许您通过实现模式提供程序接口来支持"交互模式".对于此按钮示例,Invoke模式是合适的.我们需要实现IInvokeProvider,所以将它添加到类声明中:
public class AccessibleButtonAutomationPeer :
FrameworkElementAutomationPeer,
IInvokeProvider
Run Code Online (Sandbox Code Playgroud)
(IInvokeProvider正在使用Windows.UI.Xaml.Automation.Provider命名空间.)
然后重写GetPatternCore以指示它是受支持的:
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Invoke)
{
return this;
}
return base.GetPatternCore(patternInterface);
}
Run Code Online (Sandbox Code Playgroud)
并实现IInvokeProvider.Invoke方法:
public void Invoke()
{
((AccessibleButton)Owner).DoClick();
}
Run Code Online (Sandbox Code Playgroud)
(为了支持这一点,我将AccessibleButton.OnPointerPressed方法的主体移动到它自己的DoClick()方法中,以便我可以从这里调用它.)
要测试此项,请使用旁白器选择按钮,然后按Caps Lock + Space以调用控件的默认功能.它将使用Invoke方法调用DoClick().
AutomationPeer类支持比这更多的功能.如果我开始实施它,我会更新这篇文章的更多细节.
| 归档时间: |
|
| 查看次数: |
2805 次 |
| 最近记录: |