If you haven't heard, accessibility is one of the most important aspects of a Web site experience.

By using the accessibility features in Silverlight™ 2, you can provide the best experience for all users. Building a rich Internet experience can be a daunting task when you have to balance a cool visual design with usability.

Usability goes beyond the initial determination that a user interface (UI) "makes sense" as the UI has to be accessible to everyone. Silverlight 2 enables building a cool and accessible experience, whether you are building an entire Silverlight application or just a few Silverlight controls. This article provides you with guidelines for taking advantage of these features and building an accessible Silverlight application.

Along with the visual tree of elements, your Silverlight 2 application has a corresponding accessibility tree.

If you attempted to add accessibility to your Silverlight 1 content, you probably found that there wasn't much support except for something analogous to "alt" text for screen readers. Silverlight 2 on the other hand provides necessary features that you can build on.

In general, when you build your Web application with accessibility in mind, there are a general set of areas to think about:

  • Screen reader support.
  • Keyboard navigation.
  • High contrast presentation.

Ensuring Your Silverlight 2 Content Supports Screen Readers

Silverlight 2 provides information to screen readers about your application via the new UI Automation framework. At the application level, you work with UI Automation using the AutomationProperties class and its corresponding properties. When creating custom controls or extending controls, you work with AutomationPeer and the UI Automation provider interfaces. This article looks at some important UI Automation concepts you should be aware of as you build your Silverlight 2 application.

Silverlight Accessibility Tree

Your Silverlight 2 application is comprised of many visual elements from Borders to Control-based elements. For the most part, you can split the visual elements into two types: simple visuals that usually derive directly from the FrameworkElement class, or functional controls that derive from the Control class. A TextBlock, Image, or MediaElement are examples of simple visuals while a Button, TextBox, or ListBox are examples of functional controls.

Along with the visual tree of elements, your Silverlight 2 application has a corresponding accessibility tree. UI Automation presents three accessibility views of the visual tree: a control view, a content view, and a raw view. Generally, all elements that derive from Control show up in the control view while elements that derive directly from FrameworkElement show up in the content view. TextBlock can appear in either the content view when used inside a control or data template or the control otherwise. If you create custom Silverlight controls, you can identify whether it’s a control, content, or both (or none).

There are different ways to think of elements being visible or invisible. Silverlight 2 reports elements whose Visibility property is equal to Visibility.Collapsed as hidden, but reports elements that are in the tree and "hidden" from view as being visible elements. This distinction is important because you might style your app to have different UI "modes" by just z- ordering the elements. If you have reasons for not setting the Visibility property, then you should at least disable controls that are "hidden" from view to ensure that screen readers don't attempt to interact with them.

XAML Tag Your Elements

As you develop your Silverlight application, you sometimes need to provide additional accessibility information to ensure your content is readable. For example, screen readers won't know anything about your Image element except that it is an image. As with HTML, you need to provide "alternative" text-based information. With Silverlight, you provide alternative accessibility information by using the AutomationProperties static class.

There are cases when you won't have to add additional markup via AutomationProperties. For example, controls that have text in them (like Buttons) already provide default information. In other cases, you do need to provide additional data.

Using AutomationProperties is very easy both in your XAML markup and in code. Using the Image element as an example, you set the AutomationProperties.Name attribute with XAML markup like this:

<Image x:Name="image" Source="/dogandcats.png"AutomationProperties.Name="Image of a dog andcat on a couch"/>

In code, you use the appropriate attached property set/get method:

AutomationProperties.SetLabeledBy(this.nameInput, this.nameLabel);

For best practices on providing good alternative text, see the MSDN technical article "Creating Text Equivalents for Images" (http://msdn.microsoft.com/en-us/library/ms971334.aspx).

Sometimes you might have a TextBox, Image, or other control labeled with text. For example, a TextBox for the user's name might have text to the left specifying "Name:". You can use the TextBlock element to provide that static text label, and the AutomationProperties.LabeledBy property to tell that the TextBlock is labeling the TextBox. Because Silverlight 2 does not support element Binding syntax (using the ElementName syntax) to set the LabeledBy property in XAML, you have to resort to some code, like this XAML:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="Name:" x:Name="nameLabel"/>
    <TextBox Width="100" x:Name="nameInput"/>
</StackPanel>

Then you set the LabeledBy property like so:

AutomationProperties.SetLabeledBy(this.nameInput, this.nameLabel);

To properly support screen readers, you need to ensure that all your non-text controls that show up in the accessibility tree provide at least the AutomationProperties.Name value. I recommend that you spend the time to provide other values such as HelpText. There are some great accessibility verification tools recently released by Microsoft that work great with UI Automation. Check it out by searching for Microsoft Accessibility Labs on MSDN.

UI Automation and Microsoft Active Accessibility Screen Readers-Bridging the Gap

As I've mentioned earlier, Silverlight 2 relies on the operating system's UI Automation support. This does not imply that only UI Automation-based screen readers are supported. On supported operating systems, Microsoft® Active Accessibility®-based screen readers can read Silverlight 2 content via the UI Automation UIA-to-MSAA Bridge. Because the accessibility technologies are somewhat different, not all data transfers into Microsoft Active Accessibility properties and some concepts are simplified.

For more information on the UIA-to-MSAA bridge, see the Windows Automation API 3.0 Overview article by Masahiko Kaneko in this issue. In addition, you can search MSDN for Active Accessibility Bridge to UI Automation for specific details on the limitations.

Ensure Keyboard Interactivity

Creating an accessible Silverlight application means creating a keyboard-accessible application. Try using your application with only a keyboard to identify where functionality is unavailable to keyboard-only users. Sometimes you'll find that you require mouse actions to use certain features. Other times you'll find that you cannot tab to an element.

With Silverlight, you provide alternative accessibility information by using the AutomationProperties static class and attached properties.

By thinking about keyboard accessibility during application design and development, you will avoid these types of issues. For more information on keyboard best practices, see Guidelines for Keyboard User Interface Design in MSDN (http://msdn.microsoft.com/en-us/library/ms971323.aspx).

IsTabStop and Tab Order

With the new keyboard and focus model in Silverlight 2, you can create a keyboard-friendly experience. You specify what controls can receive focus via the IsTabStop property. Most Silverlight controls, such as Button, already set the IsTabStop property to true. After you design the UI, take the time to set the TabIndex property to control the tab order. One thing to note is that only Control-based elements can receive focus.

Image and TextBlock (Non-Control-based Elements)

If you don't think about keyboard accessibility, you might add interactivity to an Image, Path, or MediaElement with mouse input, but visual elements that don’t derive from the Control class cannot receive focus. When you enable mouse actions on these types of elements, you may also want to enable the functionality with a keyboard command or with a control in the UI.

Alternatively, if you want to enable focus on an Image, you can create a custom UserControl element that contains the Image and add your keyboard logic there. Do note that you will also need to provide a focus visual indication, as described later in this article.

Custom Keyboard Actions

The trick in providing custom keyboard actions with a hotkey combination is to make sure your combination doesn't conflict with the browser keyboard actions because the browser will always win.

A good keyboard combination that I've used is combining a number key with Shift and Control keys. For example, to provide keyboard hotkeys for a particular view in my UI, I listen (hook up event handlers) for the Shift, Control, and number keys associated with the view. I add a KeyDown event handler to the root visual of my application since keyboard events bubble when not handled:

if (e.Key == Key.D1 &&
   ((Keyboard.Modifiers &
   (ModifierKeys.Control | ModifierKeys.Shift)) ==
   (ModifierKeys.Control | ModifierKeys.Shift)))
{
    // Perform hotkey action here
}

Regardless of what custom keyboard actions you add you need to let users know that they exist. You can do this by setting the AutomationProperties.AcceleratorKey property. In addition, you should add a tooltip or UI that describes the hotkey combination.

With Great Power Comes Great Responsibility

As you develop a great UI with complex gradients and cool graphics, you need to ensure you have a good experience with high contrast settings. I won't go so far as to say you shouldn’t make your UI cool; just put in the extra effort to make an accessible experience. Here are a few things to think about:

  • Design with accessibility in mind.
  • Support different text sizes or browser zoom.
  • Honor high contrast settings.

Design with Accessibility in Mind

Using XAML and styling your application is great, but you can create some ugly UI that doesn't present well to users who need higher contrast for readability.

One important thing you can do during your design is to convey information with visual cues other than color. For example, if you highlight particular list items with a red font, you could also bold them, so the user has a non-color cue to distinguish highlighted items. You can optionally add some sound as the user moves over list items to note that the list item is "active".

To help you understand some of the ways people might use your application, think about what your application would look like if you printed it on a grayscale printer. Think about what it would be like to use it with the keyboard only. Think about whether your application is useable with the sound turned off. Finally, think about whether you could easily explain how to use your app over the phone. All of these will help your design be more usable for more people in more situations.

Support Changing Font Sizes

Silverlight 2 doesn't automatically change size based upon the computer's DPI settings nor does the content automatically change size based upon the browser's zoom or text size settings. There are three ways that you can scale your content to ensure your application can provide a large font experience: based upon the Web browser's zoom setting, based upon a user-selectable UI, and based upon a use-selectable font size UI. The last option only focuses on scaling the text size vs. scaling the whole UI.

Creating an accessible Silverlight application means creating a keyboard-accessible application.

Modern Web browsers have support for whole page zooming. When users zoom, the Silverlight browser plug-in receives a resize event. Silverlight provides a public Resized event that, with a little code in your application’s Loaded event, you can use to dynamically resize your Silverlight content:

App.Current.Host.Content.Resized += new EventHandler(Content_Resized);

In the XAML, just put a ScaleTransform that you will use when the Silverlight plug-in resizes:

    <UserControl.RenderTransform>
        <TransformGroup>
            <ScaleTransform x:Name="zoomTransform" ScaleX="1" ScaleY="1"/>
        </TransformGroup>
    </UserControl.RenderTransform>

Lastly, apply the scale as a factor of your application’s size:

void Content_Resized(object sender, EventArgs e)
{
    
    System.Windows.Interop.Content content = App.Current.Host.Content;
    
    double scalePlayerX = (content.ActualWidth / this.Width);
    double scalePlayerY = (content.ActualHeight / this.Height);
    
    this.zoomTransform.ScaleX = scalePlayerX;
    this.zoomTransform.ScaleY = scalePlayerY;
}

A second approach is based upon the same code that you use for scaling based upon the Web browser's zoom except you provide your own UI for scaling.

The last approach is to provide an option to increase the font size. Silverlight 2 does not recognize the browser's text size settings, so you need to provide the user with a custom UI (as simple as a set of buttons for selecting text size). Adjusting the font size can be a great approach if you have a lot of text and the overall UI doesn't need scaling. Since adjusting the font size causes the text to take up more space, you need to use layout elements such as Grid and StackPanel instead of hard coding widths/heights. Silverlight elements inherit the FontSize property throughout, so setting it at the root of your application causes the value to propagate.

Bring Contrast to Your UI

Supporting high contrast is an important part to making your application accessible. Silverlight 2 provides the SystemParameters.HighContrast value to indicate when you should render in a high contrast mode. A high contrast mode can be as simple as omitting non-important images, gradients, or patterns behind text to more complex styling that makes your application design a bit simpler. In addition, a high contrast mode should remove or reduce transition animations, including the use of flashing.

You can take advantage of Silverlight's styling system to provide additional styles for use in high contrast scenarios. Silverlight 2 does not ship with high contrast styles for built-in controls, so you will need to create this as you style your application.

Expression Blend provides support for creating custom styles for your controls. I recommend creating two styles that you can switch between based upon the SystemParameters.HighContrast value. There is one catch: you can only apply a Silverlight control style once, and it has to be before or during the control's constructor. The more holistic approach is defining custom control styles during application startup, but you can apply a custom style in your control's constructor as well:

public class MyButton : Button
{
    public MyButton()
    {
        if (SystemParameters.HighContrast)
        {
            this.Style = (Style)Application.
            Current.Resources["btnContrast"];
            }
        }
    }
}

For an example of a Silverlight control "theme" framework, see Nikhil Kothari's blog for details (http://www.nikhilk.net/Silverlight-Themes.aspx).

Custom Controls/UI

So far, I've addressed application-level accessibility, but what’s good for the application developer is good for the control developer. There are a few more concepts that you need to understand first though.

Derive from Existing Controls

The Silverlight team has spent a lot of time making their controls accessible; you should try to derive from the closest Silverlight control. In addition, you need to extend the control’s AutomationPeer, which encapsulates accessibility functionality. If you can't find an AutomationPeer that matches your needs, then you should at least derive from FrameworkElementAutomationPeer.

Implement AutomationPeer and Associated Provider Interface

The AutomationPeer class exposes UI Automation by rolling up most of the non-pattern related UI Automation properties exposed by the AutomationElementIdentifiers class.

… when you design, do it with accessibility in mind.

Silverlight primarily chooses to focus on AutomationPeer concepts where it can. The best way to describe this is to say that the AutomationPeer class provides the necessary default UI Automation property values, and you identify a control’s accessibility support via functions rather than a role.

UI Automation identifies control functionality by a set of interfaces called control patterns. For example, to identify that you can "invoke" a control, you implement the IInvokeProvider interface in your control's AutomationPeer. To add a control pattern, you create a new AutomationPeer class and override its GetPattern method to return the interface corresponding to the pattern requested. Now that you have a custom AutomationPeer class, you need to make your custom control return an instance of it. Override the OnCreateAutomationPeer method on your control and return a new instance of your custom AutomationPeer. Listing 2 is an example of adding the IToggleProvider to a custom AutomationPeer created for a light switch control. The important parts of the custom control are in Listing 1.

To simplify technology and focus on the purpose of Silverlight, Silverlight supports only the APIs for creating provider-side UI Automation information. Silverlight does not provide the client-side UI Automation APIs.

Change is Good, But Notify Others

Because accessibility properties change often, screen readers rely on change notification to be efficient. Change notification covers such things as knowing when focus changes, knowing when a control becomes disabled, and knowing when control pattern properties change.

Silverlight provides two methods to raise a change notification: You use the AutomationPeer.RaisePropertyChangedEvent method to signal property changes, and use the AutomationPeer.RaiseAutomationEvent method to signal other types of automation changes.

Luckily, Silverlight already tells screen readers about most changes for you. Silverlight provides notifications to UI Automation clients for the AutomationPeer IsEnabled, IsOffscreen, Name, and ItemStatus values. In addition, Silverlight provides structure change notifications that tell you when items are added and removed from the visual tree. By using or deriving from a Silverlight control, you also take advantage of control-specific notifications, such as when a CheckBox is checked.

If you create your own control with its own AutomationPeer functionality, then you are responsible for identifying and notifying others about changes. See Listing 1 and Listing 2 for an example of raising property changes.

Provide Focus Indication

Visually, your control can do most anything. When people talk about accessibility support, one important visual is focus. In Silverlight 2, the control template and styling model is very rich, but what doesn't exist is a common definition for visually identifying focus.

If your control derives from a common Silverlight control, you should use the FocusVisualElement identification defined for the control and just restyle it as necessary. Using Silverlight's Visual State Manager (VSM), you can provide a custom control template that defines a new focus element.

If your control is totally unique, you should create your custom focus visual and add code in the GotFocus and LostFocus event handlers to show and hide the focus indicator. You should also create a control template and provide a named focus element, similar to what Silverlight does.

High Contrast

Lastly, instead of putting the onus on the application developers using your custom control, you should add the logic necessary to customize the controls visual style based upon the high contrast option mentioned earlier in this article.

OS Limitations

For Silverlight 2, the operating system and, to some extent, the browser dictate the level of accessibility that Silverlight can provide.

Silverlight is a Web browser plug-in based upon either Mozilla plug-in or Microsoft ActiveX technology, depending upon the browser. The Web browser is responsible for providing operating system interaction and notifications with the plug-ins contained on a Web page. In some cases, a plug-in can work directly with the operating system and bypass the browser.

Silverlight can provide accessibility information when used inside of browsers running on operating systems that support the UI Automation specification. Currently, Microsoft Windows XP and later support UI Automation; Novell has made a commitment to supporting the UI Automation interfaces on Linux. Currently, Apple’s OS X operating system does not support UI Automation, and the Mozilla plug-in technology does not support interaction with the OS X accessibility framework.

Conclusion: Silverlight’s Accessible Future

With Silverlight 2, you can control high contrast styles, keyboard navigation, and screen reader support. You can even take advantage of UI Automation wherever it’s implemented. Silverlight’s new features can help you build Web applications and controls that support accessibility, so all users can gain enjoyment and value from your work. And remember, when you design, do it with accessibility in mind.