1

I have a WPF application which prints 1 to 50 numbers and both XAML and code are given below. My requirement is to read out the label values with screen reader NVDA every time when a new content is set. My question is how to achieve readout the content which changes dynamically? Could you please help me to achieve this? Thanks

My XAML is

<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>

My code behind file is

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.";
        }
    }
}
Simant
  • 3,142
  • 4
  • 32
  • 61

2 Answers2

1

I should probably have this as a comment to your question but I think it might help lead you to the right answer so wanted to post as an answer instead. I understand accessibility as it relates to web applications but I don't have experience with WPF apps but perhaps this similarity will help.

With html, you can use the aria-live property on an element so that when text inside it changes, the change will be announced. You can control whether just the small snippet of text that changed is announced or if the entire element is announced.

For example:

<span aria-live="true">You have <span id="timeleft">X</span> seconds left</span>

If "timeleft" is changed to 5, the screen reader will just announce "5". But that probably won't make sense just hearing "5". You can use the aria-atomic property so that the entire text is read. ("Atomic" meaning "one unit")

<span aria-live="true" aria-atomic="true">You have <span id="timeleft">X</span> seconds left</span>

Now when X is changed to 5, the screen reader will say "You have 5 seconds left". The entire <span> element is read.

So, how does this relate to your original question? You should be able to use the automation properties to do something similar. In particular, the LiveSetting property. Even though this blog, ".NET Framework 4.7.1 Accessibility and WPF Improvements", is a year old (Sept 2017), it has some good information regarding the LiveSetting property.

slugolicious
  • 15,824
  • 2
  • 29
  • 43
0

I have used AutomationProperties.LiveSetting="Polite" in the Label control and in the Code section I have created AutomationPeer to raise a PropertyChanged event to UIA. This LiveSettings feature is only available .NET framework 4.7.1 and onwards.

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>

Code

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);  
        }       
    }
}
Simant
  • 3,142
  • 4
  • 32
  • 61