如何让屏幕阅读器以类似于读取 Win32 MessageBox 的方式读取我的 WPF 消息?

问题描述 投票:0回答:6

我们有一个 WPF 桌面应用程序,需要显示一些自定义消息窗口。我无法让屏幕阅读器(例如 Freedom Scientific 的 JAWS)正确朗读它们。

我想实现与显示系统消息框时相同的行为。为了进行比较,JAWS 将

System.Windows.MessageBox.Show("my message", "My Caption);
宣布为 “我的标题对话框。我的消息。确定按钮”。这太完美了。

当我的消息窗口打开(仅包含

TextBlock
和 OK
Button
)时,会宣布窗口标题,并宣布“确定”按钮具有焦点,但未宣布
TextBlock
消息。

这是一个显示问题的简单测试应用程序。当然,我们真正的应用程序有图标和其他状态文本。

<Window x:Class="Jaws_MessageBox_Test.MyMessageBox"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Jaws_MessageBox_Test"
        mc:Ignorable="d"
        Title="MyMessageBox" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock x:Name="mainLabel" Grid.Row="0">Hi there, this is a test to see if JAWS will read the main textbloc when shown.</TextBlock>
        <Button Grid.Row="1" Margin="5" HorizontalAlignment="Right" Padding="10,0,10,0"  IsDefault="True" x:Name="closeButton" Click="closeButton_Click">_Close</Button>
    </Grid>
</Window>

当我使用以下方式显示此内容时:

var mb = new MyMessageBox();
mb.ShowDialog();

屏幕阅读器宣布:“MyMessageBox.关闭按钮”,因此它不会像系统消息框那样读取 TextBlock。

我使用 Windows SDK

inspect
accevent
工具发现的是

  • 系统消息框的辅助功能类型是“对话框”,但 WPF 对话框的辅助功能类型是“窗口”。这可能很重要。没有 UI 自动化控制类型的对话框 https://msdn.microsoft.com/en-us/library/ms749005(v=vs.110).aspx 。这可能是 WPF 中的错误或限制吗?

  • 我尝试在窗口上设置各种“AutomationProperties”附加属性,以便

    AutomationPeer
    拥有更好的信息,但当
    ShowDialog
    运行时,这些信息都不会被读取。

  • 由于

    TextBlock
    无法接收输入焦点,因此甚至无法通过 Tab 键读取文本。我暂时使用只读
    TextBox
    来获得焦点,但体验仍然是错误的,我们的盲人用户不应该仅仅为了读取简单的状态消息而进行 Tab 切换。

  • 作为实验的一部分,我还尝试为消息窗口创建自己的派生

    AutomationPeer
    ,但启动对话框时不会自动读取任何
    Core
    方法内容。自动化子列表确实将标题栏对象列为第一个子对象,而这是系统消息框的最后一个子对象,尽管我现在看不到更改它的方法。

我非常感谢任何帮助创建一个基于 WPF 的自定义消息框,为盲人用户提供完整、适当的可访问性。

c# wpf xaml jaws-screen-reader section508
6个回答
4
投票

您必须告诉自动化 API 您的窗口是一个 MessageBox。 为此,请将此代码添加到您的窗口

protected override AutomationPeer OnCreateAutomationPeer()
{
    return new MessageBoxWindowAutomationPeer(this);
}

并将此类添加到您的项目中

public class MessageBoxWindowAutomationPeer : WindowAutomationPeer
{
    private const string WC_DIALOG = "#32770";

    public MessageBoxWindowAutomationPeer(Window owner)
        : base(owner)
    {
    }

    protected override string GetClassNameCore()
    {
        return WC_DIALOG;
    }

    protected override string GetLocalizedControlTypeCore()
    {
        return "Dialogfeld";
    }

    protected override bool IsContentElementCore()
    {
        return true;
    }

    protected override bool IsControlElementCore()
    {
        return true;
    }
}

由于我们不需要在我们的应用程序中进行本地化,因此“DialogFeld”是德语本地化控件类型。本地化这一部分是您必须自己找出的部分。 ;-)


1
投票

在 Textblock 内运行时设置 AutomationProperties.HelpText

举个例子:

<TextBlock>
    <Run Text="aTextString" AutomationProperties.HelpText="ATextString"/>
</TextBlock>

<TextBlock>
    <Run Text="aTextString" AutomationProperties.HelpText="{Binding Text, RelativeSource={RelativeSource self}}"/>
</TextBlock>

0
投票

通过阅读,问题出在 Jaws 而不是 WPF,因为它往往不读取标签和 TextBlock 上的静态文本 - 奇怪的行为。

解决方法可能是使用文本框,设置 BorderStyle = None 并在其顶部放置一个矩形,填充 = 白色,不透明度 = 0.01。这将阻止用户将注意力集中在 TextBox 上,并且意味着文本将不是静态的,并且 Jaws 应该自动读取文本。 。 .


0
投票

有一件事,必须是 Jaws 才能读取您的应用程序弹出的对话框吗?

您是否考虑过使用 system.speech.synthesis.speechsynthesizer 在弹出对话框时说出文本 - 只是一个想法!


0
投票

我不知道这是否是正确的解决方案,但这可以按照 JAWS 18 的要求工作。

<Window ...>
<UserControl>
    <StackPanel>
        <TextBlock Name="MessageText" ... />
        <Button Name="OKButton" ...../>
    </StackPanel>
</UserControl>
</Window>

然后在加载窗口时聚焦按钮。 所以我将 stackpanel 包裹在 usercontrol 元素内。


0
投票

我的解决方案是将“关闭”按钮集中在“Window Loaded”事件处理程序中,即在加载对话框后调用

closeButton.Focus()
。不知何故,这使得 JAWS 屏幕阅读器读出对话框中的所有文本,包括 TextBlock 元素的文本。就我而言,NVDA 不需要这样的修复。

修改后的对话框 XAML 将如下所示(为 Window 元素添加了

Loaded="MyMessageBox_Loaded"
属性):

<Window x:Class="Jaws_MessageBox_Test.MyMessageBox"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Jaws_MessageBox_Test"
        mc:Ignorable="d"
        Title="MyMessageBox" Height="300" Width="300"
        Loaded="MyMessageBox_Loaded">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock x:Name="mainLabel" Grid.Row="0">Hi there, this is a test to see if JAWS will read the main textbloc when shown.</TextBlock>
        <Button Grid.Row="1" Margin="5" HorizontalAlignment="Right" Padding="10,0,10,0"  IsDefault="True" x:Name="closeButton" Click="closeButton_Click">_Close</Button>
    </Grid>
</Window>

那么 C# 代码将如下所示:

public partial class MyMessageBox : Window
{
    public MyMessageBox()
    {
        InitializeComponent();
    }

    private void MyMessageBox_Loaded(object sender, RoutedEventArgs e)
    {
        closeButton.Focus();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.