Narrator reads collapsed content

WPF, hide collapsed content to be ignored by the narrator

Hidden maintains

Last week, I worked on some accessibility issues. One of them was the windows narrator reading collapsed content. Hidding the content from the narrator was a little harder than I would have expected when starting working on the issues.

The WPF application is using an MVVM pattern where controls are hidden and shown by changing the Visibility property. For users that look at the screen, this works fine. However, when navigating the screen with the windows narrator, the collapsed content was still read to the user. When looking deeper, content in WPF that is collapsed is removed from the visual tree and should not be read by the narrator.

Fortunately, I found some hints to make a workaround. By overriding the OnCreateAutomationPeer method, you can give a hint to the narrator to read or not read the element. The method IsControlElementCore in the AutomationPeer class gives a hint on if a control is a Control element if so the narrator skips the control. This can be used to skip your content when hidden:

public class MyButton : Button
{
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new MyAutomationPeer(this);
    }
}

public class MyAutomationPeer : ButtonBaseAutomationPeer
{
     public MyAutomationPeer(Button button): base(button) {}

     protected override bool IsControlElementCore()
     {
          return Owner.Visible != Visiblity.Collapsed;
     }
}  

In the XAML I updated the controls to my own controls and now the collapsed content is hidden from the narrator.

Some links:
https://stackoverflow.com/questions/50125307/narrator-reads-hidden-elements-in-scan-mode
https://social.msdn.microsoft.com/Forums/azure/en-US/42d6b7b3-6378-4cbb-9209-24bcd0d47e73/narrator-is-reading-wpf-controls-that-are-hidden-or-collapsed-how-to-stop-reading-controls-which?forum=wpf

Image by:Malcolm Lightbody
Advertisement

11 thoughts on “Narrator reads collapsed content”

  1. I need to implement something similar for views. When the narrator is reading my view, it first reads control on the base page (that are now hidden) and then reads the view controls. Can you please help me with it.

    Like

    1. The code above checks on collapsed, not on hidden. So you have to collapse the view to remove it from the visual tree. I did add some code to check if a parent control is collapsed (in the IsControlElementCore method). Some controls are composed of multiple sub elements, which can lead to some problems. As last resort you can just remove the text when the control is collapsed. Getting to to work right is in most cases lots of try and retry. You can also try .net 4.8 preview release: https://go.microsoft.com/fwlink/?linkid=2032091. The accessibility should be improved a lot and if you are able to target a newer framework it will save you a lot of time.

      Like

      1. Thank you Peter. Sorry to bother you. One last doubt. I implemented this same code for Button in my application. But now when the narrator focuses on button, it says “Directions Custom” instead of “Directions Button Double tap to select”. I was able to change it back to button using the following code:

        protected override AutomationControlType GetAutomationControlTypeCore()
        {
        return AutomationControlType.Button;
        }
        But it still does not say Double tap to select. Also on double tap, nothing happens on the focused button. Do you have any idea, how can we make it to retain it’s double tap functionality.

        Like

  2. Hi Peter! Thank you for publishing this article! I currently face the same issue with my WPF app, and tried your solution. Unfortunately, although I set up my custom classes in the same way and updated my controls, it did not help. Is there anything that you might recommend to have it working?

    Like

      1. Yes, I did confirm that the classes are actually used. Strange why it still reads the collapsed content…

        Like

      2. My application currently targets .NET framework version 4.0. I don’t think the code should be the issue since I followed the above code exactly.

        Like

      3. The code above in the post was done on 4.7.2. Many of the issues in 4.7.2 are probably fixed in 4.8. I would try to use a newer version of the .Net framework. 4.0 was EOL on 2016-01-12

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: