xiaohongshu
xiaohongshu
implementing-wpf-automation
Implements WPF UI Automation for accessibility using AutomationPeer and AutomationProperties. Use when building accessible applications or enabling screen reader support.
Full skill instructions
Implementing accessibility features using UI Automation framework.
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
<!-- 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}"/>
<!-- 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}"/>
| Value | Description |
|---|---|
| Off | No announcements |
| Polite | Announce when user is idle |
| Assertive | Announce immediately |
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";
}
}
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);
}
}
| Pattern | Purpose | Example Controls |
|---|---|---|
| IInvokeProvider | Single action | Button, MenuItem |
| IToggleProvider | Toggle state | CheckBox, ToggleButton |
| ISelectionProvider | Contains selectable items | ListBox, ComboBox |
| ISelectionItemProvider | Selectable item | ListBoxItem |
| IRangeValueProvider | Numeric range | Slider, ProgressBar |
| IValueProvider | Text value | TextBox |
| IExpandCollapseProvider | Expand/collapse | TreeViewItem, Expander |
| IScrollProvider | Scrollable content | ScrollViewer |
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);
}
}
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);
}
}
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;
}
}
}
<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>
<!-- 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";
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);
}
}
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
Windows + Ctrl + Enter: Toggle Narrator
Tab: Navigate forward
Shift + Tab: Navigate backward
Caps Lock + Up/Down: Read current item
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
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...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
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...
Display project status, active tracks, and next actions
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.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience