Skip to content
implementing-wpf-automation logo

WPF UI Automation Patterns

implementing-wpf-automation

Implements WPF UI Automation for accessibility using AutomationPeer and AutomationProperties. Use when building accessible applications or enabling screen reader support.

SKILL.md

Full skill instructions

WPF UI Automation Patterns

Implementing accessibility features using UI Automation framework.

1. UI Automation Overview

UI Automation Framework
├── Providers (Server-side)
│   ├── AutomationPeer (base class)
│   ├── FrameworkElementAutomationPeer
│   └── Custom AutomationPeers
├── Clients (Consumer-side)
│   ├── Screen readers (Narrator, JAWS)
│   ├── Testing tools
│   └── Custom automation clients
└── Automation Properties
    ├── AutomationProperties.Name
    ├── AutomationProperties.HelpText
    └── AutomationProperties.LabeledBy

2. AutomationProperties

2.1 Basic Properties

<!-- Name - primary identifier for screen readers -->
<Button Content="Submit"
        AutomationProperties.Name="Submit form"/>

<!-- Name for image buttons (no text content) -->
<Button AutomationProperties.Name="Close window">
    <Image Source="/​Icons/​close.png"/>
</​Button>

<!-- HelpText - additional description -->
<TextBox AutomationProperties.Name="Email address"
         AutomationProperties.HelpText="Enter your email in format [email protected]"/>

<!-- LabeledBy - reference to label element -->
<Label x:Name="UsernameLabel" Content="Username:"/>
<TextBox AutomationProperties.LabeledBy="{Binding ElementName=UsernameLabel}"/>

2.2 Additional Properties

<!-- AcceleratorKey - keyboard shortcut hint -->
<Button Content="_Save"
        AutomationProperties.AcceleratorKey="Ctrl+S"/>

<!-- AccessKey - mnemonic key -->
<Button Content="_File"
        AutomationProperties.AccessKey="Alt+F"/>

<!-- ItemStatus - current state information -->
<ListBoxItem AutomationProperties.ItemStatus="Selected, 3 of 10"/>

<!-- ItemType - type description for list items -->
<ListBoxItem AutomationProperties.ItemType="Email message"/>

<!-- LiveSetting - for dynamic content updates -->
<TextBlock AutomationProperties.LiveSetting="Polite"
           Text="{Binding StatusMessage}"/>

2.3 LiveSetting Values

ValueDescription
OffNo announcements
PoliteAnnounce when user is idle
AssertiveAnnounce immediately

3. Custom AutomationPeer

3.1 Basic Custom Peer

namespace MyApp.Controls;

using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;

public class RatingControl : Control
{
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        nameof(Value), typeof(int), typeof(RatingControl),
        new PropertyMetadata(0));

    public int Value
    {
        get => (int)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    }

    public int MaxValue { get; set; } = 5;

    // Create custom AutomationPeer
    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new RatingControlAutomationPeer(this);
    }
}

public class RatingControlAutomationPeer : FrameworkElementAutomationPeer
{
    public RatingControlAutomationPeer(RatingControl owner)
        : base(owner)
    {
    }

    private RatingControl RatingControl => (RatingControl)Owner;

    // Return control type for screen readers
    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Slider;
    }

    // Return class name
    protected override string GetClassNameCore()
    {
        return nameof(RatingControl);
    }

    // Return accessible name
    protected override string GetNameCore()
    {
        var name = base.GetNameCore();

        if (string.IsNullOrEmpty(name))
        {
            return $"Rating: {RatingControl.Value} of {RatingControl.MaxValue} stars";
        }

        return name;
    }

    // Return help text
    protected override string GetHelpTextCore()
    {
        return "Use arrow keys to change rating";
    }
}

3.2 Implementing Automation Patterns

namespace MyApp.Controls;

using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;

public class RatingControlAutomationPeer : FrameworkElementAutomationPeer,
    IRangeValueProvider
{
    public RatingControlAutomationPeer(RatingControl owner)
        : base(owner)
    {
    }

    private RatingControl RatingControl => (RatingControl)Owner;

    // Expose supported patterns
    public override object? GetPattern(PatternInterface patternInterface)
    {
        if (patternInterface == PatternInterface.RangeValue)
        {
            return this;
        }

        return base.GetPattern(patternInterface);
    }

    // IRangeValueProvider implementation
    public bool IsReadOnly => false;

    public double LargeChange => 1;

    public double SmallChange => 1;

    public double Maximum => RatingControl.MaxValue;

    public double Minimum => 0;

    public double Value => RatingControl.Value;

    public void SetValue(double value)
    {
        if (value < Minimum || value > Maximum)
        {
            throw new ArgumentOutOfRangeException(nameof(value));
        }

        RatingControl.Value = (int)value;
    }

    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Slider;
    }

    protected override string GetClassNameCore()
    {
        return nameof(RatingControl);
    }
}

4. Common Automation Patterns

PatternPurposeExample Controls
IInvokeProviderSingle actionButton, MenuItem
IToggleProviderToggle stateCheckBox, ToggleButton
ISelectionProviderContains selectable itemsListBox, ComboBox
ISelectionItemProviderSelectable itemListBoxItem
IRangeValueProviderNumeric rangeSlider, ProgressBar
IValueProviderText valueTextBox
IExpandCollapseProviderExpand/​collapseTreeViewItem, Expander
IScrollProviderScrollable contentScrollViewer

5. Raising Automation Events

5.1 Property Changed Event

public class CustomControlAutomationPeer : FrameworkElementAutomationPeer
{
    public void RaiseValueChanged(int oldValue, int newValue)
    {
        // Notify automation clients of value change
        RaisePropertyChangedEvent(
            RangeValuePatternIdentifiers.ValueProperty,
            (double)oldValue,
            (double)newValue);
    }

    public void RaiseSelectionChanged()
    {
        RaiseAutomationEvent(AutomationEvents.SelectionPatternOnInvalidated);
    }
}

5.2 From Control

public class RatingControl : Control
{
    private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = (RatingControl)d;

        // Get automation peer and raise event
        var peer = UIElementAutomationPeer.FromElement(control) as RatingControlAutomationPeer;
        peer?.RaiseValueChanged((int)e.OldValue, (int)e.NewValue);
    }
}

6. Focus and Keyboard Navigation

6.1 Keyboard Support

public class RatingControl : Control
{
    public RatingControl()
    {
        // Enable keyboard focus
        Focusable = true;
        FocusVisualStyle = (Style)FindResource(SystemParameters.FocusVisualStyleKey);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        switch (e.Key)
        {
            case Key.Left:
            case Key.Down:
                if (Value > 0)
                {
                    Value--;
                    e.Handled = true;
                }
                break;

            case Key.Right:
            case Key.Up:
                if (Value < MaxValue)
                {
                    Value++;
                    e.Handled = true;
                }
                break;

            case Key.Home:
                Value = 0;
                e.Handled = true;
                break;

            case Key.End:
                Value = MaxValue;
                e.Handled = true;
                break;
        }
    }
}

6.2 Focus Visual

<Style TargetType="{x:Type local:RatingControl}">
    <Setter Property="FocusVisualStyle">
        <Setter.Value>
            <Style>
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border BorderBrush="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
                                    BorderThickness="2"
                                    CornerRadius="2"
                                    Margin="-2"/>
                        </​ControlTemplate>
                    </​Setter.Value>
                </​Setter>
            </​Style>
        </​Setter.Value>
    </​Setter>
</​Style>

7. Screen Reader Announcements

7.1 Live Regions

<!-- Status updates announced when changed -->
<TextBlock x:Name="StatusText"
           AutomationProperties.LiveSetting="Polite"
           AutomationProperties.Name="Status"/>
// Update status - screen reader will announce
StatusText.Text = "3 items selected";

7.2 Programmatic Announcements

using System.Windows.Automation.Peers;

public static void Announce(string message)
{
    var peer = FrameworkElementAutomationPeer.FromElement(Application.Current.MainWindow);

    if (peer != null)
    {
        peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
    }
}

8. Accessibility Checklist

Essential

  • All interactive elements have AutomationProperties.Name
  • Images have descriptive names or are marked decorative
  • Form fields are labeled (LabeledBy or Name)
  • Focus is visible and logical order is correct
  • Keyboard navigation works for all functionality

Enhanced

  • HelpText provides additional context
  • AcceleratorKey documents shortcuts
  • LiveSetting for dynamic content
  • Custom controls have AutomationPeers
  • Color contrast meets WCAG guidelines

9. Testing Accessibility

9.1 Using Inspect.exe

Tools location:
Windows SDK → bin → [arch] → inspect.exe

Usage:
1. Run inspect.exe
2. Hover over UI elements
3. View automation properties
4. Verify Name, ControlType, Patterns

9.2 Using Narrator

Windows + Ctrl + Enter: Toggle Narrator
Tab: Navigate forward
Shift + Tab: Navigate backward
Caps Lock + Up/​Down: Read current item

10. References

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View