Skip to main content

WinForms Accessibility for Developers

Overview

Welcome to the WinFormsAccessibility for Developers course. As a developer, you are responsible for implementing accessible solutions for end users, and a little work up front on your part goes a long way towards integrated, accessible code in the final product.

  • As a result of this course you will be able to:
  • Implement programmatic access in your products
  • Explain how WinForms uses Microsoft Active Accessibility (MSAA) to create accessible code
  • Recognize WinForms-specific accessibility code issues and fixes
  • Create accessible, customized WinForms controls

Welcome

Each platform has its own way of providing programmatic access to users. In Windows Forms (WinForms), developers wrap unmanaged COM controls in managed code and use the Microsoft Active Accessibility (MSAA) API to expose information to users.

This course is organized to help you locate information quickly when you need it, and is laid out in the following manner:

  • Programmatic Access
  • Keyboard Navigation
  • System Settings
  • API Information
  • Custom Controls

Programmatic Access

Programmatic access involves ensuring all user interface (UI) elements are exposed programmatically to the AT. Without it, the application programming interfaces (APIs) for Assistive Technology (AT) cannot interpret information correctly, leaving the user unable to use the products sufficiently, or force AT to use undocumented programming interfaces or techniques never intended to be used as an “accessibility” interface. When UI elements are exposed to AT, it is able to determine what actions and options are available to the user. Without proper programmatic access, a user may receive useless or erroneous, or even no information about what they are doing in the program.

Programmatic Access in WinForms

Programmatic access in WinForms is provided when using Winforms common controls. Here are the basic guidelines for creating accessible applications with common controls, which will be explained further in this section:

  • Leave accessibility properties as is in almost all cases.
  • Setting the “text” property will visually and programmatically set the name.
  • Include a Winforms control “label” before the controls such as list boxes, edit boxes, or other controls that do not have a useful name on the control itself.
  • Make sure the elements are in the “TabIndex” properly so the MSAA tree will be correct.

If these guidelines do not apply, you may need to set the AccessibleName property. This should only be done in rare circumstances where the default information is missing or incorrect. More information about AccessibleName is available in the Accessibility Properties section of this course.

Leave Properties As-Is

In almost all cases, leave the accessibility properties as is. You should not need to change the accessibility properties of a control, except in circumstances where:

  • The functionality of the control has been modified
  • A label cannot be used to set the property
  • The property does not inherit the control’s name

In these cases, other properties such as the Name, Value, Role, DefaultAction, etc. may need to be amended to provide the correct use of the control. These situations normally arise in the case of custom controls. More information about custom controls can be found in the Custom Controls section of this course.

More information about MSAA properties can be found on MSDN.

Programmatically, any WinForms control can also reference these properties.

CButton1->AccessibleDescription
C#Button1.AccessibleDescription

One place to find the properties for a control is in the Properties pane in Visual Studio.

Properties in Visual Studio are located in the Properties pane

Setting the Text Property

Setting the text property will visually and programmatically set the name. This can be done through either the IDE, or through the code directly. Controls with ControlStyles.UseTextForAccessibility set will use the text of the control to set the name automatically. For example, TextBox will use the text when TextBox.Text contains text, but not if it is empty or set to null.

Include a WinForms Control Label

Include a Winforms control “label” before controls that do not have a useful name on the control itself such as list boxes or edit boxes. For example, you can add a Label to the top of a Form that provides instructions to the user on how to input data in the controls on the form. Label controls can be also used to display run time information on the status of an application. For example, you can add a Label control to a form to display the status of each file as a list of files is processed.

The following code example demonstrates how to create a Label control that has a three-dimensional border and contains an image.

public void CreateMyLabel()















{















   // Create an instance of a Label.















   Label label1 = new Label();















 















   // Set the border to a three-dimensional border.















   label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;















   // Set the ImageList to use for displaying an image.















   label1.ImageList = imageList1;















   // Use the second image in imageList1.















   label1.ImageIndex = 1;















   // Align the image to the top left corner.















   label1.ImageAlign = ContentAlignment.TopLeft;















 















   // Specify that the text can display mnemonic characters.















   label1.UseMnemonic = true;















   // Set the text of the control and specify a mnemonic character.















   label1.Text = "First &Name:";















 















   /* Set the size of the control based on the PreferredHeight and PreferredWidth values. */















   label1.Size = new Size (label1.PreferredWidth, label1.PreferredHeight);















 















   //...Code to add the control to the form...















}

Edit Boxes: Edit boxes include a “text” property, but still need a preceding label. In this case, to provide programmatic access:

  • The label needs to be correct in the tab order (before TextBox).
  • TextBox.Text should be null or empty.

Then the label will provide the "text" as the MSAA Name.

Make Sure Elements are in theTabIndex

When the user presses the TAB key, the input focus is set to the next control in the tab order. The tab order can be manipulated by setting the control's TabIndex property value. Make sure the elements are in the “TabIndex” properly so the MSAA tree is correct. This also ensures that the text labels and controls will appear properly in the tree.

All controls will automatically be given TabIndex properties as they are added to a form. In orderfor a control to be included in the tab order and receive focus, its TabStop property must be set to true.

TabIndex is set this way:

public int TabIndex {get; set;}

The TabStop is set as follows:

public bool TabStop { get; set; }

Product Y example

Now we will learn how to create an accessible product using common controls. Product eXample (Product X) is an application for users to order pizza for delivery. It allows users to select their size of pizza and toppings and provide a name for the order.

Product Y Logical Hierarchy

The first step for developing an accessible product, as already mentioned, is to map out the Logical Hierarchy for it. In the case of Product X, we will follow the English-speaking standards of top to bottom and right to left for navigation.

So what would the Logical Hierarchy of Product X look like? Click the items on the page in the order you think they would appear.

Activity: show Product X-WF image, and allow learners to click on: Pizza Image, Good Pizza title, Name, Pizza Size, Toppings, Cancel and Order. Then submit to see if they are correct. Final hierarchy should be:

Order Form container

Main Menu

     Menu Item

Image

Text

Label

     Text entry field

Radio Box

     Button

     Button

Label

List

     Checkbox

     Checkbox

     Checkbox

Button

Button

Determining Controls

Now that you have created a Logical Hierarchy for Product X, it is time to chart out the controls and properties needed to provide programmatic access in the application. Using the chart below, we can determine the name and type of WinForms control needed for each item in the Logical Hierarchy.

Accessible Logical UI Hierarchy ItemNameWinForms Control
Form containerPizza Order FormForm1
ImageGood Pizza Company LogoPictureBox
TextGood Pizza CompanyLabel
LabelCustomer NameLabel
Text Entry FieldEnter Your NameTextbox
Radio BoxPizza Size OptionsGroupBox
Radio ButtonSmall pizza $6.00RadioButton
Radio ButtonLarge pizza $10.00RadioButton
ListAvailable Toppings $0.75 eachCheckedListBox
List ItemPepperoniItem of CheckedListBox
List ItemSausageItem of CheckedListBox
List ItemMushroomsItem of CheckedListBox
ButtonCancel the OrderButton
ButtonPlace the OrderButton

Keyboard Navigation

By using IAccessible navigation, a client can move through the MSAA object hierarchy and dynamically discover what UI elements and objects are available. Therefore, all UI elements must support IAccessible navigation methods.

The two IAccessible navigation modes are spatial navigation (up, down, left, right) and logical navigation (next, previous, parent, first child, last child).

Spatial Navigation

  • A client uses spatial navigation to move from one UI element to another based on their on-screen position. However, an accessible object must support spatial navigation only to its siblings. Spatial navigation is relevant only within the context of a single container.

This form of navigation has the most use for an end user when the UI elements are arranged in a grid, where it is meaningful to navigate left, right, up, and down. For example, consider a list view control in large icon view. Because all icons are children of the parent list view control (that is, they are siblings to each other) and they are arranged in a near-grid pattern, spatial navigation is a natural means for moving between UI elements and should be supported.

Logical Navigation

  • Clients can use logical navigation to explore the MSAA object hierarchy and discover what controls and elements exist. To do this, clients rely on proper support for navigation from an IAccessible object to identify its parent, children, and siblings. This form of navigation also provides the foundation on which MSAA clients can develop more powerful capabilities, such as hands-free navigation of UI elements.

For the list view control just described in Spatial Navigation, logical navigation provides a simple mechanism for visiting each list view icon exactly one time. To do this, the client could begin with the list view's IAccessible object, navigate to its first child, and then repeatedly navigate next until accNavigate fails. Beginning with the list view's last child and repeatedly navigating previous achieves the same result.

Because logical navigation is widely used by MSAA clients, all servers must ensure full support for this form of navigation.

Labels and Form Fields

Labels are used to give a name to form field controls so that the user understands the functionality of the control that follows. As previously noted, you must provide access via keyboard navigation to all controls. Provide an access key for any Label which precedes a control that a user can navigate to in order to make the editable field easy to reach. Also be sure that any Label control which describes a TextBox control precedes it in the tab order so that the Label is set as the Name of the TextBox control.

Keyboard Access Keys

You must plan for effective keyboard interactions in your product. Think through the navigation for the product, which items should receive keyboard focus, and how non-text items will be labeled to provide the best experience for users.

What are Access Keys?

One piece of providing keyboard navigation in WinForms is the use of access keys. An access key is an alphanumeric key (sometimes called a hot key or mnemonic) that users can employ instead of a pointing device to activate controls. In most cases, an access key correlates to a designated character in a control label. For example, to open the File menu, for which the access key is typically F, the user would press ALT+F. Access keys are associated only with controls that have text labels.

Access Keys Navigation

As a secondary method for navigation, you may choose to add access keys to all menu items, which provides users the ability to navigate to them and select or interact with them. Adding Access keys is useful, but not required. If you do add access keys, it should invoke a single command.

Creating Access Keys

Access keys allow users to navigate to a control, or part of a control, in order to interact with it. Adding an access key in WinForms is done using the “&” character in the following manner:

  • Add the “&” character to the Text property of any control that requires user access.
  • Add the “&” character to the Text property of any label that precedes a control which requires user access. In this scenario you must also set the label’s UseMnemonic property to “true” in order to create focus on the next control in the tab order when the user presses the access key.

Info Icon: Keyboard Best Practices For more information on keyboard best practices, see the Guidelines for Keyboard User Interface Design on the MSDN Web site.

High DPI

When your application detects that a user has high DPI settings implemented, it should respond by automatically scaling the application to meet the user settings. In the case of WinForms, this is done by setting up code using the Form.AutoScaleBaseSize property, such as:

public virtual Size AutoScaleBaseSize {get; set;}

Further information on setting your product up for high DPI can be found on MSDN.

High Contrast

High contrast mode is a system setting that improves readability by using contrasting colors and font sizes that are beneficial for visually impaired users. When designing your application, it is very important to use system colors. Be sure not to hard-code colors, and have alternative color icons available for high-contrast setting users.

In WinForms, the SystemInformation.HighContrast Property should be included in the code. When implemented, it allows the application to determine whether the high contrast mode is set.

If the SystemInformation.HighContrast is true, then the application must:

  • Display all user interface elements using the system color scheme
  • Provide an alternative way of understanding information conveyed only through color. This is often done using visual cues or sound. For example, a list of items with ones that need to be reviewed showing with red font, you could also add an icon, bold the font, or provide other options for users to identify those items in red font.
  • Omit any images or patterns which appear behind text, such as watermarks.

When the application starts it should check the settings for high contrast and respond to the system event UserPreferenceChanged, which is raised whenever the value of HighContrast changes.

Enabling High Contrast Settings

Let’s walk through the process of enabling high contrast settings in an application.

The SystemColors Class is used to change the color settings of items in the UI to the user-selected system colors. The first step in enabling high contrast mode is to create a method to set the colors of UI elements to the system colors.

// C#















private void SetColorScheme()















{















   if (SystemInformation.HighContrast)















   {















      companyLabel.BackColor = SystemColors.Window;















      companyLabel.ForeColor = SystemColors.WindowText;















   }















   else















   {















      companyLabel.BackColor = Color.Blue;















      companyLabel.ForeColor = Color.Yellow;















   }















}

Call the SetColorScheme

Next, you need to call the SetColorScheme procedure in the form constructor (Public Sub New () in Visual Basic, public class Form1 in Visual C#, and Public Form1 in Visual J#). To access the constructor in Visual Basic, you must expand the region labeled “Windows Form Designer generated code.”

// C#















public Form1()















{















   InitializeComponent();















   SetColorScheme();















}

Respond to UserPreferenceChanged Event

Once the color scheme has been set into place, you must create an event procedure, with the appropriate signature, to respond to the UserPreferenceChanged event.

// C#















public void UserPreferenceChanged(object sender, 















Microsoft.Win32.UserPreferenceChangedEventArgs e)















{















   SetColorScheme();















}

Hook Up Event Procedure

Now add code to the form constructor, after the call to InitializeComponents, to hook up the event procedure to the system event. This method calls the SetColorScheme procedure.

// C#















public Form1()















{















   InitializeComponent();















   SetColorScheme();















   Microsoft.Win32.SystemEvents.UserPreferenceChanged 















      += new Microsoft.Win32.UserPreferenceChangedEventHandler(















      this.UserPreferenceChanged);















}

Release the Event

The system event code runs a thread separate from the main application, so you must be sure to release the event when the application closes so that the code hooked up to the event doesn’t continue to run after the program is closed. To do this, add code to the form Dispose method, before the call to the Dispose method of the base class, to release the event when the application closes. To access the Dispose method in Visual Basic, you must expand the region labeled “Windows Form Designer generated code.”

// C#















protected override void Dispose( bool disposing )















{















   if( disposing )















   {















      if (components != null) 















      {















         components.Dispose();















      }















   }















   Microsoft.Win32.SystemEvents.UserPreferenceChanged 















      -= new Microsoft.Win32.UserPreferenceChangedEventHandler(















      this.UserPreferenceChanged);















   base.Dispose( disposing );















}

Other Considerations

Some applications use sound to convey information to users, such as a beep when an error is made. If your application uses sound, then you must supply the information conveyed by an alternative means as well.

Some alternatives you may wish to consider are:

Custom Controls

If you choose not to use common controls for your application, additional work is required to help ensure that programmatic access is correctly exposed to AT. This section of the course will give you the basics of MSAA, its notable properties, and how it relates to custom controls.

Choosing Custom Controls

Before choosing a custom control as the appropriate route for your application, be sure to think through the control to decide whether it might be possible to take advantage of a common control and its accessible properties instead. Creating a custom control means that many default accessibility properties are not available to you, and can increase the time and workload to create the control.

Review your planned custom control using these criteria:

  • Does the control represent only one element (in the Logical Hierarchy)?
  • Does it function exactly like a Win32 or WinForms common control?
  • Can its functionality be described with a single MSAA role?
  • When you set all of the accessible properties, will the control’s functionality be fully exposed?

If the custom control meets all of these criteria: Use the appropriate Win32 or WinForms common control to build your control.

If the custom control does not meet all of these criteria: Build a custom control, then override properties as necessary to create the customization of the control.

What is MSAA?

WinForms uses MSAA, which is a COM-based API that can be used by AT products to provide programmatic access to its users. MSAA implements the IAccessible interface to accomplish its programmatic exposure. If you plan to customize controls or build a completely custom control, you need to understand how to make those controls accessible using MSAA.

MSAA Clients

MSAA is designed to help AT clients interact with standard and custom UI elements of applications and the operating system. It notifies the client about the ability to access, identify, or interact with the UI elements of an application. Clients include AT, automated testing tools, and some computer-based training applications.

To convey information about changes in the server’s UI, clients register, or “set a hook,” to listen to changes on the applications. The client receives notifications of specific changes through a mechanism called Window Events, or WinEvents. More information about WinEvents is available on the WinEvents page.

MSAA Servers

Applications that interact with and provide information to clients are called servers. This includes any control, module, or applications which implements MSAA. A server uses MSAA to provide information about its UI elements to clients.

An application is considered an MSAA server if it:

  • Exposes relevant properties.
  • Supports proper navigation.
  • Supports proper hit testing.
  • Generates appropriate WinEvents.

Depending on the application's design and implementation, some of these requirements may be satisfied by MSAA's default support.

Exposing Relevant Properties

Not all IAccessible properties and methods are relevant for all UI elements. The properties supported by an object vary depending on the type of UI element it represents. Servers must support the following properties and methods for every object:

  • Name
  • Role
  • State
  • Location (and IAccessible::accHitTest)
  • Parent (and IAccessible::accNavigate)
  • Child Count

The following properties must be supported if they are applicable to the object:

  • Keyboard Shortcut
  • Default Action (and IAccessible::accDoDefaultAction)
  • Value

The following properties must be supported if the object has children:

  • Child
  • Focus
  • Selection (and IAccessible::accSelect)

The following properties are optional, but they provide useful information about the object. In particular, the Description property should be supported to describe bitmaps and other visual elements:

  • Description
  • Help or Help Topic

Accessibility Properties

Adding accessibility information to your code provides necessary information to users of AT about what your application or product does, and how it can be used. Please refer to the Programmatic Access Guidelines earlier in this course for guidelines about setting properties.

You may see these default MSAA properties in your code:

  • AccessibleName provides a descriptive label for a control, often the text contained by the control such as “Cancel” on a button.
  • AccessibleRole provides information about the user interface and functionality of the control. For example, if you are using a PictureBox as a chart, you might select “chart” as the AccessibleRole rather than “PictureBox.”
  • AccessibleDefaultActionDescription describes the functionality, or action, of the control. For example, a button labeled "Print" has a default action of "Press," with no value.

Pitfall: Do Not Use AccDescription The AccDescription property hasn’t been consistently or correctly used and it is not supported in transition to UI Automation. You are discouraged from using or populating a new data in this property. If more information is needed for accessibility and automation scenarios, refer to properties for UI Automation Elements and Control Patterns.

Pitfall: Visual Studio Editor AccessibleName When setting the AccessibleName property in VS Editor, you may run into this problem. If you set the AccessibleName property and then delete it, it will then always set the name as “” unless you fill it again with text, and never rely on the Text property or the Label preceding it. A solution to this is to manually delete the code below to allow the proxy to do its work:

this.listView1.AccessibleName = "";

WinEvents

Window Events (WinEvents) are used by MSAA to notify clients of changes in an application's user interface, such as creating and destroying objects or changing any MSAA property of a UI element.

WinEvent support is a fundamental part of the Windows operating system. It provides:

  • A simple way for clients to register for event notifications.
  • A mechanism for injecting client code into servers.
  • Routing of events from servers to interested clients.
  • Automatic event generation for most HWND-based controls.

AccessibleObject Class

Another way to create more custom controls with programmatic access is to utilize the AccessibleObject namespace class. This process requires that you set very detailed MSAA properties. AccessibleObject is a wrapper for MSAA information that is passed from Win32 controls. To use the AccessibleObject, you must add a reference to the Accessibility assembly installed with the .NET Framework. Windows Forms only supports MSAA 2.0.

Learn more about the AccessibleObject class at

Control.ControlAccessibleObject Members,

AccessibleObject Class, and

Control.AccessibilityNotifyClients Method.

Customizing Properties

In some situations you may want to customize the default MSAA properties for a WinForm control. For example, if the default Help property of the button is not the desired value, you can create your own AccessibleObject, inherit from ControlAccessibleObject, and override the Help Property.

class MyButton : Button















    {















        protected override AccessibleObject CreateAccessibilityInstance()















        {















            return new MyButtonBaseAccessibleObject(this);















        }















 















        public class MyButtonBaseAccessibleObject : ButtonBaseAccessibleObject















        {















            public MyButtonBaseAccessibleObject(Control owner)















                : base(owner)















            {















            }















 















            public override string Help















            {















                get















                {















                    return "this is my button's help";















                }















            }















        }















 















}

Walk-Through: Create an Accessible Custom Control

This section of the course will walk you through the process of creating an accessible custom control in WinForms. In this example, you will create a chart control with a class name of Demo.

The following walk-through will give you step-by-step knowledge on how to create accessible custom controls.

Info Icon:HandlingControls with Multiple Children

In cases where your control has multiple children, you must override the following two methods of AccessibleObject to return back the child.

/// <include file='doc\AccessibleObject.uex' path='docs/doc[@for="AccessibleObject.GetChild"]/*' />















        /// <devdoc>















        ///    <para>When overridden in a derived class, gets the accessible child corresponding to the specified 















        ///       index.</para>















        /// </devdoc>















        public virtual AccessibleObject GetChild(int index) {















            return null;















        }















 















        /// <include file='doc\AccessibleObject.uex' path='docs/doc[@for="AccessibleObject.GetChildCount"]/*' />















        /// <devdoc>















        ///    <para> When overridden in a derived class, gets the number of children















        ///       belonging to an accessible object.</para>















        /// </devdoc>















        public virtual int GetChildCount() {















            return -1;















        }

Step by Step

Step 1: Set Accessible Attributes

When creating a custom control, you must define the accessible attributes for the control. In the case of the chart, the following accessible attributes need to be addressed:

AttributeValue
RoleAccessibleRole.Chart
StateAccessibleStates.ReadOnly
NameMy chart
HelpHelp for my chart
ValueValue for my chart

Step 2: Create and Draw the Basic Outline

To create the custom control:

  1. Right click Project item in Solution Explorer
  2. Click Add new items
  3. Select Custom Control
  4. Name the control Demo
  5. Save

Draw some basic shapes in the control. You may notice it uses System.Drawing.SystemColors. This will cause the chart control to be subject to changes in the system colors.

protected override void OnPaint(PaintEventArgs pe)















        {















            BackColor = SystemColors.ControlLight;















            Pen p = new Pen(SystemColors.HotTrack);















            Rectangle rect = pe.ClipRectangle;















            pe.Graphics.DrawLine(p, new Point(rect.Left + 3, rect.Bottom - 3), new Point(rect.Right - 3, rect.Bottom - 3));















            pe.Graphics.DrawLine(p, new Point(rect.Left + 3, rect.Bottom - 3), new Point(rect.Left + 3, rect.Top + 3));















 















            p = new Pen(SystemColors.Highlight);















            pe.Graphics.DrawLine(p, new Point(rect.Left + 3, rect.Bottom - 3), new Point(rect.Left + (rect.Right - rect.Left) / 2, rect.Top + (rect.Bottom - rect.Top) / 2));















            pe.Graphics.DrawLine(p, new Point(rect.Left + (rect.Right - rect.Left) / 2, rect.Top + (rect.Bottom - rect.Top) / 2), new Point(rect.Left + (rect.Right - rect.Left) * 3 / 4, rect.Top + (rect.Bottom - rect.Top) * 3 / 4));















            pe.Graphics.DrawLine(p, new Point(rect.Left + (rect.Right - rect.Left) * 3 / 4, rect.Top + (rect.Bottom - rect.Top) * 3 / 4), new Point(rect.Right - 3, rect.Top + 3));















 















            base.OnPaint(pe);















        }

Step 3: Create a Class Derived FromControlAccessibleObject

After creating the custom control initial setup, we now need to create a class inside the Demo control. We will name it DemoControlAccessibleObject, which is derived from ControlAccessibleObject, as following:

public class DemoControlAccessibleObject : ControlAccessibleObject















        {















            public DemoControlAccessibleObject(Demo ctrl)















                : base(ctrl)















            {















            }















        }

Step 4: Override the Accessible Attributes

Next, we must override some accessible attributes of ControlAccessibleObject, and provide the values we assigned in the table from step 1.

Role should be Chart

public override AccessibleRole Role















            {















                get















                {















                    return AccessibleRole.Chart;















                }















            }

State should be ReadOnly

public override AccessibleStates State















            {















                get















                {















                    return AccessibleStates.ReadOnly;















                }















            }

Name should be My Chart

public override string Name















            {















                get















                {















                    return "my chart";















                }















            }

Help should be Help for My Chart

public override string Help















            {















                get















                {















                    return "help for my chart";















                }















            }

Value should be Value for My Chart

public override string Value















            {















                get















                {















                    return "Value for my chart";















                }















            }

Step 5: OverrideCreateAccessibilityInstanceMethod

The next step is to override the CreateAccessibilityInstance method for the control.

protected override AccessibleObject CreateAccessibilityInstance()















        {















            return new DemoControlAccessibleObject(this);















        }

Step 6: Add Reference for Accessibility.dll

To add the Accessibility.dll reference:

  1. Right click Reference in Solution Explorer
  2. Click Add Reference…
  3. Add Accessibility.dll

Step 7: Build and add the Demo Control to the Form

Next, we build and add the Demo control to the form.

Here is the partial source code of the Demo control:

public partial class Demo : Control















    {















        public Demo()















        {















            InitializeComponent();















            BackColor = Color.Green;















        }















 















        protected override void OnPaint(PaintEventArgs pe)















        {















            // Do some drawing here.















 















            base.OnPaint(pe);















        }















 















        // Overridden to return the custom AccessibleObject 















        // for the entire chart.















        protected override AccessibleObject CreateAccessibilityInstance()















        {















            return new DemoControlAccessibleObject(this);















        }















 















                // Inner class ChartControlAccessibleObject represents accessible information associated with the ChartControl.















        // The ChartControlAccessibleObject is returned in the ChartControl.CreateAccessibilityInstance override.















        public class DemoControlAccessibleObject : ControlAccessibleObject















        {















            //Demo demoControl;















 















            public DemoControlAccessibleObject(Demo ctrl)















                : base(ctrl)















            {















            }















            //{















            //    demoControl = ctrl;















            //}















 















            // Gets the role for the Chart. This is used by accessibility programs.















            public override AccessibleRole Role















            {















                get















                {















                    return AccessibleRole.Chart;















                }















            }















 















            // Gets the state for the Chart. This is used by accessibility programs.















            public override AccessibleStates State















            {















                get















                {















                    return AccessibleStates.ReadOnly;















                }















            }















 















            public override string Name















            {















                get















                {















                    return "my chart";















                }















            }















 















            public override string Help















            {















                get















                {















                    return "help for my chart";















                }















            }















        }















 















    }

Step 8: ImplementWinEvents

The example control does not need an event implemented, since the object doesn’t change. In the case of controls where change occurs, however, you must carefully implement WinEvents. Information on how to do this can be found at the Generating Appropriate WinEvents page on MSDN.

Test the Control

You can now test the accessible attributes you just defined to ensure programmatic access is exposed correctly. To see the accessibility attributes of this chart control, you can use AccExplorer to capture the control. When tested, the chart gives the following info.

Also the chart control is subject to the change of system color. When system changes to “High Contrast Black”, the chart will change, using the system color settings for High Contrast.

When system changes to “Windows Standard”, the chart will change as following:

Support Hit Testing

MSAA uses hit testing to drill down through the IAccessible hierarchy to retrieve an IAccessible object for the UI element at a specified screen location. Oleacc’s AccessibleObjectFromPoint API relies on proper support for IAccessible::accHitTest to find the appropriate UI element. Therefore, all visual UI elements must support hit testing through the accHitTest method.

Tools & Resources

Now that you’ve learned more about developing accessible products and services, you may want to explore the subject further. Here are some online resources you might find helpful.

Course Completion

Congratulations, you have completed the WinForms Accessibility for Developers course.

You now have an increased understanding on how to use WinForms common controls to create more accessible applications. You can also see the benefits of including accessibility into your product development cycle in a programmatic way to enhance the development process. Further courses are available on how to write accessible code and address platform-specific issues for accessibility. You can also consult the Microsoft Accessibility developer portal on MSDN for more information.

The courses in the Accessibility Training for Developers include:

  1. Introduction to Accessibility
  2. General Accessibility for Developers
  3. Windows (Win 32) Accessibility for Developers
  4. WinForms Accessibility for Developers
  5. WPF Accessibility for Developers
  6. Silverlight Accessibility for Developers
Rate: