Perplexed Owl Random Ponderings

Benjamin ‘Benilda’ Key:

Providing Accessibility Information in a .NET Windows Forms application

Windows Forms applications provide two mechanisms for providing accessibility information.

In many cases the required accessibility information can be provided using the following properties of the Control Class in the System.Windows.Forms Namespace: the Control.AccessibleDefaultActionDescription Property, the Control.AccessibleDescription Property, the Control.AccessibleName Property, and the Control.AccessibleRole Property. This feature is almost enough to meet WCAG Success Criterion 4.1.2: Name, Role, Value. WCAG Success Criterion 4.1.2: Name, Role, Value requires that state information be provided as well. Unfortunately, there is not a property in the Control Class for state information.

In many cases, the built in Windows Forms support is sufficient and therefore there is no need to specifically provide state information.

If you do need to provide state information, it will take a bit more effort. In this case, you will need to use the AccessibleObject Class and the Control.CreateAccessibilityInstance Method.

Using the Accessible* Properties of the Control Class

The following code demonstrates the use of the Control.AccessibleDescription Property and the Control.AccessibleName Property of the Control Class.


private void InitGoButton()
{
    string[] paths = {Application.StartupPath, goButtonImage};
    goButton = new Button();
    goButton.AccessibleDescription = goButtonAccessibleDescription;
    goButton.AccessibleName = goButtonAccessibleName;
    goButton.BackgroundImage = Image.FromFile(Path.Combine(paths));
    goButton.BackgroundImageLayout = ImageLayout.Center;
    goButton.Click += new EventHandler(this.goButton_Click);
    goButton.Location = new Point(goButtonLeft, buttonsTop);
    goButton.Name = goButtonName;
    goButton.Size = new Size(buttonsWidth, buttonsHeight);
    goButton.TabIndex = 0;
    goButton.UseVisualStyleBackColor = true;
}

Source: Control Accessible Properties Example


In this case, the Button object provides the state. However, since an image is used instead of text, it does not provide the name. Therefore the Control.AccessibleDescription Property and the Control.AccessibleName Property of the Control Class are used. Since the state is provided by the Button object, setting these properties suffice to meet WCAG Success Criterion 4.1.2: Name, Role, Value.

There is one special use case for the Control.AccessibleDescription Property. Screen readers such of JAWS often read dialog static text when a form or dialog box is first displayed. The purpose of dialog static text is to provide instructions or other useful information. You might think that JAWS will include the text in Label objects in this dialog static text. Unfortunately, this does not work in a Windows Forms application. The solution is to include the Label for sighted users and set the Control.AccessibleDescription Property for the form object to the text that is displayed in the label objects. The Control Accessible Properties Example demonstrates this technique.

Using the AccessibleObject Class and the Control.CreateAccessibilityInstance Method

If you need to provide state information you will need to use the AccessibleObject Class and the Control.CreateAccessibilityInstance Method to provide your own implementation of the IAccessible interface since the Control Class class does not provide an AccessibleState property.

The following is a sample implementation of the AccessibleObject Class from the Create Accessibility Instance Example.



public class AccSampleCtrlAccessibleObject : Control.ControlAccessibleObject
{
    private AccSampleCtrl ctrl;

    public AccSampleCtrlAccessibleObject(AccSampleCtrl owner) : base(owner)
    {
        ctrl = owner;
    }

    public override string Name
    {
        get
        {
            string name = ctrl.AccessibleName;
            if (name != null)
            {
                return name;
            }
            return ctrl.Text;
        }
        set
        {
            base.Name = value;
        }
    }

    public override AccessibleRole Role
    {
        get
        {
            return AccessibleRole.Chart;
        }
    }

    public override AccessibleStates State
    {
        get
        {
            return AccessibleStates.ReadOnly;
        }
    }

    /* Code omitted for brevity. */
}

Next you need to override the Control.CreateAccessibilityInstance Method as follows.


protected override AccessibleObject CreateAccessibilityInstance()
{
    return new AccSampleCtrlAccessibleObject(this);
}

See the the Create Accessibility Instance Example for more.

References