Accessibility is about making your applications usable by people with limitations that prevent or impede the use of conventional user interfaces (UIs). Some applications have accessibility requirements imposed by law, but it is a good idea to address these issues regardless of legal requirements in order to ensure that your applications have the largest possible audience.
There are a wide variety of disabilities or impairments, including limitations in mobility, vision, color perception, hearing, speech, cognition, and literacy. However, you can address most requirements by following some standard guidelines. This means providing:
The Silverlight control library provides built-in keyboard support and support for screen readers, which take advantage of accessibility frameworks that already exist for use with HTML and other UI technologies. This built-in support enables a basic level of accessibility that you can customize with very little work by setting a handful of properties. If necessary, you can also add similar support to your own custom controls, although this is an advanced scenario.
The Silverlight data binding, style, and template systems make it easy to implement support for user display settings and alternative UIs. Silverlight also provides APIs that enable you to manipulate media files and access any alternative tracks and captioning that they provide.
This QuickStart provides an overview of the accessibility support built into Silverlight and describes how to customize this support or implement your own.
This QuickStart contains the following sections:
Many user accessibility needs are fulfilled by Assistive Technology (AT) products installed by the user or by tools and settings provided by the operating system. This includes things like screen readers, screen magnification, and high contrast settings. The following illustration shows some of the tools provided by Windows 7.

AT products include a wide variety of software and hardware. These products work through the standard keyboard interface and accessibility frameworks that reports information about the content and structure of a UI to screen readers and other ATs. Examples of AT products include:
Applications that have good keyboard and screen reader support will generally work well with a variety of AT products. In many cases, Silverlight works with these products out of the box. However, you will typically want to modify some settings for optimal behavior or to implement additional support.
To provide good keyboard support, you must ensure that every part of your application can be used with a keyboard. If your application makes heavy use of the standard controls, you are most of the way there already. The Silverlight control library provides built-in keyboard support including tab navigation, text input, and control-specific support such as arrow key navigation among ListBox items and DataGrid cells.
To use the keyboard with a control, it must have input focus, and to receive input focus (without using the mouse), it must be accessible via tab navigation. By default, the tab order of controls is the same as the order in which they are added to a design surface, listed in XAML, or programmatically added to a container.
In most cases, the default order is the best order, especially because that is the order in which the controls are read by screen readers. However, the default order does not necessarily correspond to the visual order. The actual display position depends on the containing Panel and the values of properties such as Margin, Canvas.Top and Canvas.Left, or Grid.Row and Grid.Column.
You can ensure that the tab order matches the visual order by adjusting the XAML, or you can override the default tab order by setting the TabIndex property, as shown in the following example of a Grid layout that uses column-first tab navigation.
<!--Custom tab order.--> <Grid> <Grid.RowDefinitions>...</Grid.RowDefinitions> <Grid.ColumnDefinitions>...</Grid.ColumnDefinitions> <TextBlock Grid.Column="1" HorizontalAlignment="Center">Groom</TextBlock> <TextBlock Grid.Column="2" HorizontalAlignment="Center">Bride</TextBlock> <TextBlock Grid.Row="1">First name</TextBlock> <TextBox x:Name="GroomFirstName" Grid.Row="1" Grid.Column="1" TabIndex="1"/> <TextBox x:Name="BrideFirstName" Grid.Row="1" Grid.Column="2" TabIndex="3"/> <TextBlock Grid.Row="2">Last name</TextBlock> <TextBox x:Name="GroomLastName" Grid.Row="2" Grid.Column="1" TabIndex="2"/> <TextBox x:Name="BrideLastName" Grid.Row="2" Grid.Column="2" TabIndex="4"/> </Grid>
Tab navigation cycles through all controls in both the browser host and the application, and then repeats the cycle from the beginning. Users can navigate backward through the tab order by pressing SHIFT+TAB.
If you want to exclude a control from the tab order, you can set the IsTabStop property to false. However, you will typically do this only if you make a control non-interactive, for example by setting its IsEnabled property to false, which automatically excludes it from the tab order.
If you implement any mouse-specific interactions, you should implement keyboard equivalents. However, in order to use the keyboard with a UI element, the element must have input focus. Only classes that derive from Control support input focus and tab navigation.
You could create your own custom control, in which case you must set the IsTabStop property to true to enable input focus and provide a visual indication of the focused state using the VisualStateManager class. However, it is often easier to make use of Silverlight control composition.
For example, instead of handling a mouse event on an Image, you could wrap it in a Button to get mouse, keyboard, and focus support automatically. This is demonstrated in the following example.
<!--Don't do this.--> <Image Source="sample.jpg" MouseLeftButtonDown="Image_MouseLeftButtonDown"/>
<!--Do this instead.--> <Button Click="Button_Click"><Image Source="sample.jpg"/></Button>
Tab navigation provides a good, basic level of keyboard support, but with complex forms, you might want to add support for shortcut keys as well. This can make your application more efficient to use, even for people who use both a keyboard and a mouse.
Silverlight does not provide the kind of built-in shortcut key support that you find in Windows Presentation Foundation (WPF) or Windows Forms. One issue with shortcut keys in Silverlight is that many key combinations are intercepted by the browser host or operating system. Additionally, browser updates can add new shortcut keys at any time, creating unanticipated future conflicts.
It is possible to implement your own shortcut key support, but you should test shortcut keys in all supported browsers. To avoid conflicts, you should not use modifier keys such as CTRL, SHIFT, and ALT. However, in some cases, such as data-entry applications, this is not practical.
If you require modifier keys, one option is to require out-of-browser installation, although even in this case, you cannot use the ALT key. Another option is to use keystrokes that are less likely to cause conflict, such as number keys in combination with CTRL+SHIFT. Using number keys is also beneficial to avoid potential issues with language-dependent letter keys in localized applications.
It is important to document the shortcut keys in your application so that users are aware of them. For example, you can provide a ToolTip on a button that has a shortcut key. You can also use the convention of underlining a letter in a control label. This kind of shortcut key is called an access key or mnemonic. Of course, ToolTips are not useful without a mouse, and neither ToolTips nor underlined letters are reported by screen readers.
You can document access keys through screen readers by setting the AutomationProperties.AccessKey attached property to a string that describes the shortcut key. There is also an AutomationProperties.AcceleratorKey attached property for documenting non-mnemonic shortcut keys, although screen readers generally treat both properties the same way. In general, you should document shortcut keys in multiple ways, using ToolTips, automation properties, and written help documentation.
The following example demonstrates shortcut keys for media play, pause, and stop buttons.
<MediaElement x:Name="Movie" Source="sample.wmv"
AutoPlay="False" Width="320" Height="240"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="Play" Margin="1,2"
ToolTipService.ToolTip="shortcut key: P"
AutomationProperties.AccessKey="P">
<TextBlock><Underline>P</Underline>lay</TextBlock>
</Button>
<Button x:Name="Pause" Margin="1,2"
ToolTipService.ToolTip="shortcut key: A"
AutomationProperties.AccessKey="A">
<TextBlock>P<Underline>a</Underline>use</TextBlock>
</Button>
<Button x:Name="Stop" Margin="1,2"
ToolTipService.ToolTip="shortcut key: S"
AutomationProperties.AccessKey="S">
<TextBlock><Underline>S</Underline>top</TextBlock>
</Button>
</StackPanel>
public MainPage()
{
InitializeComponent();
Play.Click += (sender, e) => Movie.Play();
Pause.Click += (sender, e) => Movie.Pause();
Stop.Click += (sender, e) => Movie.Stop();
LayoutRoot.KeyDown += (sender, e) =>
{
switch (e.Key)
{
case Key.P: Movie.Play(); break;
case Key.A: Movie.Pause(); break;
case Key.S: Movie.Stop(); break;
}
};
}
Public Sub New()
InitializeComponent()
AddHandler Play.Click, Sub() Movie.Play()
AddHandler Pause.Click, Sub() Movie.Pause()
AddHandler [Stop].Click, Sub() Movie.Stop()
AddHandler LayoutRoot.KeyDown,
Sub(sender, e)
Select Case e.Key
Case Key.P
Movie.Play()
Case Key.A
Movie.Pause()
Case Key.S
Movie.Stop()
End Select
End Sub
End Sub
Another issue with shortcut keys in Silverlight is that Silverlight cannot receive any keystrokes unless the Silverlight plug-in itself has input focus. If the Silverlight plug-in is only part of a web page that has other content, users will need to tab to or click the plug-in before they can use the keyboard with it. If the plug-in occupies the entire page, however, you can add the following code to ensure that the plug-in receives focus as soon as the page finishes loading.
LayoutRoot.Loaded += (sender, e) =>
System.Windows.Browser.HtmlPage.Plugin.Focus();
AddHandler LayoutRoot.Loaded,
Sub()
System.Windows.Browser.HtmlPage.Plugin.Focus()
End Sub
Note that this does not prevent the browser from intercepting any shortcut key combinations that it recognizes.
Screen readers provide access to the text in an application by rendering it some other format, such as spoken language or Braille output. The exact behavior of a screen reader depends on the software and on the user configuration of the software.
For example, some screen readers read the entire application UI when the user launches or switches to the application, enabling the user to receive all of the available informational content before using tab navigation. Some screen readers also read the text associated with an individual control when it receives input focus during tab navigation. This enables users to orient themselves as they navigate among the input controls of an application. Narrator is an example of a screen reader that uses both behaviors.
On the other hand, some screen readers read the text of an application only during tab navigation. For this reason, you should ensure that all important information in your UI is part of a focusable control. For example, instead of using a TextBlock to convey application instructions in your UI, you might use a TextBox or RichTextBox with an IsReadOnly property value of true. This enables the control to receive focus while preventing user input.
To support screen readers, you must provide text alternatives to non-textual information in the UI, such as images and charts, excluding any purely decorative or structural elements. You can do this by setting the AutomationProperties.Name attached property as shown in the following example:
<Image Source="product.png" AutomationProperties.Name="An image of a customer using the product."/>
However, to support screen readers that read text only during tab navigation, you should also provide a caption using a technique such as the read-only TextBox. Alternately, you could create a custom control that enables input focus while displaying non-interactive content, or you could provide an alternate UI depending on a user setting, as described later in this QuickStart.
Screen readers use the AutomationProperties.Name property to identify controls. In most cases, you should set this property, but if a control (such as a button) already displays a text label, that text will be used as the default property value. The following example illustrates this distinction:
<StackPanel Width="100">
<StackPanel Orientation="Horizontal">
<TextBlock>Quantity</TextBlock>
<TextBox x:Name="QuantityTextBox" Width="25"
AutomationProperties.Name="Quantity"/>
</StackPanel>
<Button x:Name="SubmitButton">Place Order</Button>
</StackPanel>
During tab navigation, screen readers will ignore the TextBlock, identify the TextBox as the "quantity text box", and identify the button as the "place order button".
As you can see, the TextBox is labeled by both the TextBlock and the AutomationProperties.Name value. You can avoid the redundant labeling by setting the AutomationProperties.LabeledBy property instead, which indicates where the AutomationProperties.Name should get its value. This is shown in the following example:
<TextBlock x:Name="QuantityLabel">Quantity</TextBlock>
<TextBox x:Name="Quantity" Width="25"
AutomationProperties.LabeledBy="{Binding ElementName=QuantityLabel}"/>
You will typically provide a very brief description for AutomationProperties.Name, but this property is meant to identify the control rather than document its behavior. If a brief description is insufficient to explain the control, you can set the AutomationProperties.HelpText attached property in addition to AutomationProperties.Name.
There are several other automation properties available (including the keyboard properties described in the previous section). However, not all screen readers support all automation properties. In general, you should set all appropriate properties in order to provide the widest possible support for existing and future screen readers.
Silverlight reports information to screen readers through the UI Automation framework. The AutomationProperties class is part of this framework, but most of the support comes from a set of classes that parallel the control classes and derive from AutomationPeer.
When you create a custom control, you should also implement or extend one or more AutomationPeer subclasses to provide accessibility support. This subject is outside the scope of this QuickStart, but you can find more information in some of the MSDN topics listed at the end of this topic.
The user interface of a Silverlight application is represented by a visual tree of UI elements. The accessibility information that the UI Automation framework reports to screen readers is represented by a similar accessibility tree. You can view this accessibility tree using free tools such as UIA Verify or commercial tools such as Silverlight Spy. This is useful to confirm the values of the AutomationProperties attached properties, as shown in the following illustration.

Although the accessibility tree reports the values exposed to screen readers, it is useful to test your applications using actual screen readers. Windows provides the built-in Narrator screen reader, but other popular screen readers include NVDA (open source), JAWS, and Windows Eyes.
Screen readers will read everything displayed in the browser host along with the Silverlight content, so it is useful to perform screen-reader tests using out-of-browser mode. For more information, see Out-of-Browser Support.
Users can adjust some display settings at the operating system level or in the host browser. Some of these settings automatically affect Silverlight, while others require some additional work or separate implementation.
Users prefer to configure their display settings at a global level rather than figuring out how to adjust each individual application, so it is a good idea to take advantage of global settings whenever possible. In some cases, however, you will want to provide additional support, and Silverlight enables you to implement arbitrary display customizability that has no relationship to operating system or browser settings.
Adjusting display sizes at the operating system level affects everything displayed on the monitor, including all Silverlight-based applications both inside and outside the browser.
Outside the browser, increased size settings result in fuzziness and pixelization. Inside the browser, display size settings affect the browser zoom setting (for browsers that support zoom settings), which results a smooth, vector-based scaling of browser-hosted Silverlight applications. The following illustration shows the difference between browser zoom and out-of-browser zoom.

In browsers that support zoom settings, users can set the browser zoom level independently of the operating system display settings. In this case, however, out-of-browser applications are not affected.
For Silverlight-based applications hosted in the browser, you can customize the effect of the browser zoom setting by using the Settings.EnableAutoZoom and Content.ZoomFactor properties and the Content.Zoomed event. This is useful for making dynamic layout adjustments.
You can also implement your own display size settings that works regardless of operating system and browser settings. Browser text size settings have no effect on Silverlight, so implementing your own approach is necessary if you want to scale text independently of other UI elements.
The following example provides a simple demonstration of UI and font scaling.
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<StackPanel Margin="10,5">
<TextBlock FontWeight="Bold">UI Zoom:</TextBlock>
<Slider x:Name="UIZoomSlider" Width="100" Minimum="1" Maximum="2"/>
</StackPanel>
<StackPanel Margin="10,5">
<TextBlock FontWeight="Bold">Font Zoom:</TextBlock>
<Slider x:Name="FontZoomSlider" Width="100" Minimum="15" Maximum="30"/>
</StackPanel>
</StackPanel>
<UserControl FontSize="{Binding Value, ElementName=FontZoomSlider}">
<UserControl.RenderTransform>
<ScaleTransform x:Name="transform" CenterX="150"
ScaleX="{Binding Value, ElementName=UIZoomSlider}"
ScaleY="{Binding Value, ElementName=UIZoomSlider}"/>
</UserControl.RenderTransform>
<Border BorderBrush="Black" BorderThickness="1" Background="White"
CornerRadius="3" Padding="3" Margin="2" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<StackPanel>
<TextBlock FontWeight="Bold" HorizontalAlignment="Right"
Margin="0,0,0,-7">Hello</TextBlock>
<TextBlock FontWeight="Bold">World</TextBlock>
</StackPanel>
<Ellipse Fill="Green" Height="38" Width="38"/>
</StackPanel>
</Border>
</UserControl>
</StackPanel>
Many users have difficulty distinguishing certain colors or experience discomfort when viewing UIs with bright colors or insufficient contrast. It is therefore useful to provide the option to change the default colors, or at least to switch to a high contrast mode.
If users select a high contrast setting at the operating system level, your application should respond to it and switch to high contrast mode automatically. You can do this by checking the SystemParameters.HighContrast property when your UI loads. Note, however, that your application cannot automatically detect changes to this property, so it is helpful to provide your own UI in addition to checking the operating system setting.
Another option is to use the System Colors theme provided by the Silverlight Toolkit. This theme automatically applies the current system colors (including high contrast colors) to all of the controls provided by Silverlight and the toolkit. For more information, see the Silverlight Toolkit.
The following example demonstrates how to use the Style class and the SystemParameters.HighContrast property to implement a high contrast mode.
<UserControl x:Class="QuickstartHighContrast.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="145" Width="155" Background="Transparent">
<UserControl.Resources>
<Style x:Name="ContentBlockDefaultStyle" TargetType="UserControl">
<Setter Property="Foreground" Value="Salmon"/>
</Style>
<Style x:Name="ContentBorderDefaultStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="Salmon"/>
<Setter Property="Background" Value="Bisque"/>
</Style>
<Style x:Name="ContentBlockHighContrastStyle" TargetType="UserControl">
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Name="ContentBorderHighContrastStyle" TargetType="Border">
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="Background" Value="Black"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="34"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<StackPanel x:Name="LayoutRoot" Margin="10">
<CheckBox x:Name="HighContrastCheckBox" FontWeight="Bold" Margin="0,0,0,5"
Click="HighContrastCheckBox_Click">Use High Contrast</CheckBox>
<UserControl x:Name="ContentBlock"
Style="{StaticResource ContentBlockDefaultStyle}">
<Border BorderThickness="1" BorderBrush="Black"
CornerRadius="7" Padding="0">
<Border x:Name="ContentBorder"
Style="{StaticResource ContentBorderDefaultStyle}"
BorderThickness="5" CornerRadius="3" Padding="3">
<StackPanel>
<TextBlock Margin="0,0,0,-10">Hello</TextBlock>
<TextBlock>World</TextBlock>
</StackPanel>
</Border>
</Border>
</UserControl>
</StackPanel>
</UserControl>
public MainPage()
{
InitializeComponent();
if (SystemParameters.HighContrast)
{
SetHighContrast(true);
HighContrastCheckBox.IsChecked = true;
}
}
private void HighContrastCheckBox_Click(object sender, RoutedEventArgs e)
{
SetHighContrast(HighContrastCheckBox.IsChecked.Value);
}
private void SetHighContrast(Boolean highContrast)
{
if (highContrast)
{
ContentBlock.Style =
this.Resources["ContentBlockHighContrastStyle"] as Style;
ContentBorder.Style =
this.Resources["ContentBorderHighContrastStyle"] as Style;
}
else
{
ContentBlock.Style =
this.Resources["ContentBlockDefaultStyle"] as Style;
ContentBorder.Style =
this.Resources["ContentBorderDefaultStyle"] as Style;
}
}
Public Sub New()
InitializeComponent()
If (SystemParameters.HighContrast) Then
SetHighContrast(True)
HighContrastCheckBox.IsChecked = True
End If
End Sub
Private Sub HighContrastCheckBox_Click(ByVal sender As Object,
ByVal e As RoutedEventArgs)
SetHighContrast(HighContrastCheckBox.IsChecked.Value)
End Sub
Private Sub SetHighContrast(ByVal highContrast As Boolean)
If (highContrast) Then
ContentBlock.Style =
CType(Me.Resources("ContentBlockHighContrastStyle"), Style)
ContentBorder.Style =
CType(Me.Resources("ContentBorderHighContrastStyle"), Style)
Else
ContentBlock.Style =
CType(Me.Resources("ContentBlockDefaultStyle"), Style)
ContentBorder.Style =
CType(Me.Resources("ContentBorderDefaultStyle"), Style)
End If
End Sub
Silverlight displays audiovisual media through the MediaElement class. You can use members of this class to control the media playback. For accessibility purposes, you should provide controls that enable users to play, pause, and stop the media playback as needed. You can see an example of this in the keyboard section earlier in this QuickStart.
If your application includes audio or audiovisual media, you should provide text alternatives or captions for the hearing impaired. You typically add captions directly to your media files using tools such as Expression Encoder.
Captions that are always displayed as part of the media stream are called open captions, and require no further work within the application. Captions that are optional are called closed captions, and you can display them in your application using code such as the following:
<MediaElement x:Name="media" Width="300" Height="200" MarkerReached="OnMarkerReached" Source="media.wmv"/>
public void OnMarkerReached(object sender,
TimelineMarkerRoutedEventArgs e)
{
CaptionTextBlock.Text = e.Marker.Text;
}
Public Sub OnMarkerReached(ByVal sender As Object,
ByVal e As TimelineMarkerRoutedEventArgs)
CaptionTextBlock.Text = e.Marker.Text
End Sub
You can also add alternate audio streams to your media files using tools such as Expression Encoder. These streams are useful to provide spoken commentary, including descriptions of the video stream for use by the vision impaired. To access these alternate streams, use the AudioStreamCount and AudioStreamIndex properties of the MediaElement class.
Silverlight enables you to create complex, visually attractive UIs, but in many cases, these UIs are not very accessible. In general, when you design your applications, you should think about how they might be used by people with limited mobility, vision, and hearing. Because AT products make extensive use of standard UI interfaces, it is particularly important to provide good keyboard and screen reader support even if you make no other adjustments for accessibility.
In many cases, you can convey essential information using multiple techniques in order to widen your audience. For example, you can highlight information using both icon and color information to help users who are color blind, and display visual alerts along with sound effects to help users who are hearing impaired.
If necessary, you can provide alternative, accessible UIs that completely remove nonessential elements and animations, and provide other simplifications to streamline the user experience. The following code example demonstrates how to display one UserControl instance in place of another depending on a user setting.
<StackPanel x:Name="LayoutRoot" Background="White">
<CheckBox x:Name="ShowAccessibleUICheckBox" Click="ShowAccessibleUICheckBox_Click">
Show Accessible UI
</CheckBox>
<UserControl x:Name="ContentBlock">
<local:ContentPage/>
</UserControl>
</StackPanel>
private void ShowAccessibleUICheckBox_Click(object sender, RoutedEventArgs e)
{
if ((sender as CheckBox).IsChecked.Value)
{
ContentBlock.Content = new AccessibleContentPage();
}
else
{
ContentBlock.Content = new ContentPage();
}
}
Private Sub ShowAccessibleUICheckBox_Click(ByVal sender As Object,
ByVal e As RoutedEventArgs)
If (ShowAccessibleUICheckBox.IsChecked.Value) Then
ContentBlock.Content = New AccessibleContentPage()
Else
ContentBlock.Content = New ContentPage()
End If
End Sub
This QuickStart has provided an overview of accessibility techniques, but there are many other resources available on the web, some of which are listed in the following See Also section. In particular, the ButtercupReader book reader provides a reference implementation of Silverlight accessibility techniques, and you can download the complete source code from CodePlex.
Comments (0)