在WPF应用程序中,如何使用屏幕阅读器在标签中动态读取变化的值?
我有一个WPF应用程序,它打印1到50个数字,下面给出了XAML和代码。我的要求是每次设置新内容时,使用屏幕阅读器NVDA读取标签值。我的问题是如何实现动态变化的内容的读出?你能帮我做到这一点吗?谢谢 我的XAML是在WPF应用程序中,如何使用屏幕阅读器在标签中动态读取变化的值?,wpf,visual-studio-2017,accessibility,ui-automation,Wpf,Visual Studio 2017,Accessibility,Ui Automation,我有一个WPF应用程序,它打印1到50个数字,下面给出了XAML和代码。我的要求是每次设置新内容时,使用屏幕阅读器NVDA读取标签值。我的问题是如何实现动态变化的内容的读出?你能帮我做到这一点吗?谢谢 我的XAML是 <Window x:Class="WPFAccessibility.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="h
<Window x:Class="WPFAccessibility.MainWindow"
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:WPFAccessibility"
mc:Ignorable="d"
Title="WPFAccessibility" Height="450" Width="800">
<Grid>
<Label Name="progressLabel" FontSize="20" Margin="50,50"></Label>
</Grid>
</Window>
我的代码隐藏文件是
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WPFAccessibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var mySource = Enumerable.Range(1, 50).ToList();
Task.Factory.StartNew(() => DoOperation(mySource));
}
private void DoOperation(List<int> values)
{
foreach (var i in values)
{
Thread.Sleep(1000);
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
Process(currentProgress);
}), DispatcherPriority.Background);
}
}
private void Process(int currentProgress)
{
progressLabel.Content = "Processing... " + currentProgress;
if (currentProgress == 50)
progressLabel.Content = "Processing completed.";
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Threading;
命名空间可访问性
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
var mySource=Enumerable.Range(1,50).ToList();
Task.Factory.StartNew(()=>DoOperation(mySource));
}
私有void操作(列表值)
{
foreach(值中的var i)
{
睡眠(1000);
var currentProgress=i;
Dispatcher.BeginInvoke(新操作(()=>
{
过程(当前进度);
}),DispatcherPriority.Background);
}
}
私有无效进程(int currentProgress)
{
progressLabel.Content=“处理…”+当前进度;
如果(当前进度==50)
progressLabel.Content=“处理已完成。”;
}
}
}
我可能应该将此作为对您问题的评论,但我认为它可能会帮助您找到正确的答案,因此我想将其作为答案发布。我理解可访问性,因为它与web应用程序有关,但我没有WPF应用程序的经验,但这种相似性可能会有所帮助
使用html,您可以对元素使用属性,这样当元素中的文本发生更改时,更改将被宣布。您可以控制是只宣布更改的文本的一小部分,还是宣布整个元素
例如:
<span aria-live="true">You have <span id="timeleft">X</span> seconds left</span>
现在,当X变为5时,屏幕阅读器会说“您还有5秒钟”。读取整个
元素
那么,这与你最初的问题有什么关系呢?您应该能够使用自动化属性来执行类似的操作。特别是LiveSetting
属性。尽管这个博客已经有一年了(2017年9月),但它有一些关于LiveSetting
属性的好信息。我在标签控件和代码部分使用了AutomationProperties.LiveSetting=“little”,我创建了AutomationPeer来向UIA引发PropertyChanged事件。此LiveSettings功能仅适用于.NET framework 4.7.1及更高版本
XMAL
<Window x:Class="WPFAccessibility.MainWindow"
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:WPFAccessibility"
mc:Ignorable="d"
Title="WPFAccessibility" Height="450" Width="800">
<Grid>
<Label Name="progressLabel" FontSize="20" Margin="50,50" AutomationProperties.LiveSetting="Polite"></Label>
</Grid>
</Window>
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WPFAccessibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static int counter = 0;
public MainWindow()
{
InitializeComponent();
var mySource = Enumerable.Range(1, 50).ToList();
Task.Factory.StartNew(() => DoOperation(mySource));
}
private void DoOperation(List<int> values)
{
foreach (var i in values)
{
Thread.Sleep(2000);
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
Process(currentProgress);
}), DispatcherPriority.Background);
}
}
private void Process(int currentProgress)
{
progressLabel.Content = "Processing... " + currentProgress;
if (currentProgress == 50)
progressLabel.Content = "Processing completed.";
var peer = UIElementAutomationPeer.FromElement(progressLabel);
if (peer == null)
peer = UIElementAutomationPeer.CreatePeerForElement(progressLabel);
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Threading;
命名空间可访问性
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
专用静态整数计数器=0;
公共主窗口()
{
初始化组件();
var mySource=Enumerable.Range(1,50).ToList();
Task.Factory.StartNew(()=>DoOperation(mySource));
}
私有void操作(列表值)
{
foreach(值中的var i)
{
《睡眠》(2000年);
var currentProgress=i;
Dispatcher.BeginInvoke(新操作(()=>
{
过程(当前进度);
}),DispatcherPriority.Background);
}
}
私有无效进程(int currentProgress)
{
progressLabel.Content=“处理…”+当前进度;
如果(当前进度==50)
progressLabel.Content=“处理已完成。”;
var peer=UIElementAutomationPeer.FromElement(progressLabel);
if(peer==null)
peer=UIElementAutomationPeer.CreatePeerForElement(progressLabel);
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WPFAccessibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static int counter = 0;
public MainWindow()
{
InitializeComponent();
var mySource = Enumerable.Range(1, 50).ToList();
Task.Factory.StartNew(() => DoOperation(mySource));
}
private void DoOperation(List<int> values)
{
foreach (var i in values)
{
Thread.Sleep(2000);
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
Process(currentProgress);
}), DispatcherPriority.Background);
}
}
private void Process(int currentProgress)
{
progressLabel.Content = "Processing... " + currentProgress;
if (currentProgress == 50)
progressLabel.Content = "Processing completed.";
var peer = UIElementAutomationPeer.FromElement(progressLabel);
if (peer == null)
peer = UIElementAutomationPeer.CreatePeerForElement(progressLabel);
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
}
}