Accessibility in Windows Store App

Introduction

In this section we see a possible use of accessibility in Windows 8 Metro Style application. With the help of this example we make a data entry forms accessible by setting automation properties on form elements. Each text box has an automation property and textblock and text values are automatically treated as automation properties. In the tab sequence the tab will cycle through controls in the order they are declared in XAML. We have customized by the tabindex setting. The automation peers can add accessibility support to your custom controls by creating automation peers.

So, we use the following steps to make this application.

Step 1 : First of all you have to create a new Metro Style Application; let us see the description with images of how you will create it.
 

  • Open Visual Studio 2011
  • File -> New -> Project
  • Choose Template -> Visual C# -> Windows Metro Style -> Application
  • Rename this Application

openpage.gif

home.gif

Step 2 : In the Solution Explorer there are two files that we will primarily work with; MainPage.xaml and MainPage.xaml.cs files. In the images folder add any image to the application and we have also added any folder such as video name in this application.

solutionexplorer.gif

Step 3 : The MainPage.xaml file is as in the following code.

Code : Let us see the code which is given below.

<UserControl x:Class="Accessibility.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    d:DesignHeight="768" d:DesignWidth="1366">

 

  <Grid x:Name="LayoutRoot" Background="Crimson">

    <!--App Orientation States-->

    <VisualStateManager.VisualStateGroups>

      <VisualStateGroup x:Name="OrientationStates">

        <VisualState x:Name="Full"/>

        <VisualState x:Name="Fill">

          <Storyboard>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="ContentRoot">

              <DiscreteObjectKeyFrame KeyTime="0">

                <DiscreteObjectKeyFrame.Value>

                  <Thickness>40,20,40,20</Thickness>

                </DiscreteObjectKeyFrame.Value>

              </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(StackPanel.Orientation)" Storyboard.TargetName="InputPanel">

              <DiscreteObjectKeyFrame KeyTime="0">

                <DiscreteObjectKeyFrame.Value>

                  <Orientation>Horizontal</Orientation>

                </DiscreteObjectKeyFrame.Value>

              </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.MaxWidth)" Storyboard.TargetName="Description">

                <DiscreteObjectKeyFrame KeyTime="0" Value="700">

                </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

          </Storyboard>

        </VisualState>

        <VisualState x:Name="Portrait">

            <Storyboard>

                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="ContentRoot">

                    <DiscreteObjectKeyFrame KeyTime="0">

                        <DiscreteObjectKeyFrame.Value>

                            <Thickness>40,20,40,20</Thickness>

                        </DiscreteObjectKeyFrame.Value>

                    </DiscreteObjectKeyFrame>

                </ObjectAnimationUsingKeyFrames>

                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.MaxWidth)" Storyboard.TargetName="Description">

                    <DiscreteObjectKeyFrame KeyTime="0" Value="700">

                    </DiscreteObjectKeyFrame>

                </ObjectAnimationUsingKeyFrames>

                    </Storyboard>

        </VisualState>

        <VisualState x:Name="Snapped">

          <Storyboard>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="ContentRoot">

              <DiscreteObjectKeyFrame KeyTime="0">

                <DiscreteObjectKeyFrame.Value>

                  <Thickness>20,20,20,20</Thickness>

                </DiscreteObjectKeyFrame.Value>

              </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(StackPanel.Orientation)" Storyboard.TargetName="InputPanel">

              <DiscreteObjectKeyFrame KeyTime="0">

                <DiscreteObjectKeyFrame.Value>

                  <Orientation>Vertical</Orientation>

                </DiscreteObjectKeyFrame.Value>

              </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.MaxWidth)" Storyboard.TargetName="Description">

                <DiscreteObjectKeyFrame KeyTime="0" Value="250">

                </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="LegalPanel">

                <DiscreteObjectKeyFrame KeyTime="0">

                    <DiscreteObjectKeyFrame.Value>

                        <Thickness>0,0,10,0</Thickness>

                    </DiscreteObjectKeyFrame.Value>

                </DiscreteObjectKeyFrame>

            </ObjectAnimationUsingKeyFrames>

            </Storyboard>

        </VisualState>

      </VisualStateGroup>

    </VisualStateManager.VisualStateGroups> 

    <Grid x:Name="ContentRoot" Background="CornflowerBlue" Margin="100,20,100,20">

      <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="*"/>

        <RowDefinition Height="Auto"/>

      </Grid.RowDefinitions> 

     <!-- Content -->

      <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Row="1" ZoomMode="Disabled">

        <StackPanel>

          <StackPanel x:Name="InputPanel" Orientation="Horizontal" HorizontalAlignment="Left">

            <StackPanel>

              <TextBlock Text="Input" Style="{StaticResource H2Style}"/>

              <TextBlock Text="Select Item:" Style="{StaticResource H3Style}"/>

              <ListBox x:Name="ItemList" Margin="0,0,20,0" HorizontalAlignment="Left">

                <ListBox.ItemTemplate>

                  <DataTemplate>

                    <TextBlock Text="{Binding Name}"/>

                  </DataTemplate>

                </ListBox.ItemTemplate>

                <ListBoxItem x:Name="Item1">

                    <TextBlock Style="{StaticResource ListBoxTextStyle}" Text="1. Creating an accessible form" />

                </ListBoxItem>

                <ListBoxItem x:Name="Item2">

                    <TextBlock Style="{StaticResource ListBoxTextStyle}" Text="2. Tab sequence" />

                </ListBoxItem>

                <ListBoxItem x:Name="Item3">

                    <TextBlock Style="{StaticResource ListBoxTextStyle}" Text="3. Override AutomationPeers" />

                </ListBoxItem>

            </ListBox>

            </StackPanel>

            <StackPanel Margin="0,31,0,0" >

              <TextBlock Text="Description:" Style="{StaticResource H3Style}"/>

              <StackPanel x:Name="Description" MaxWidth="900">                 

                  <!-- Item 1 -->

                <StackPanel x:Name="Item1Input">

                  <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap">

You can make data entry forms accessible by setting automation properties on form elements. For example, each TextBox below has an AutomationProperties.Name attached property with a value that matches the nearby label. An active screen reader will read this name when you set the focus to the text box. Additionally, TextBlock.Text values are automatically treated as AutomationProperties.Name values, giving you some built-in accessibility support.

                  <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap" Margin="0,20,0,0" Text=""/>

                </StackPanel>                 

                  <!-- Item 2 -->

                <StackPanel x:Name="Item2Input" Visibility="Collapsed">

     <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap" Text="By default, the TAB key will cycle through controls in the order they are declared in XAML. You can customize this behavior by setting the TabIndex and IsTabStop properties, as shown in the demonstration below." />

                  <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap" Margin="0,20,0,0" Text=""/>

                </StackPanel>                 

                  <!-- Item 3 -->

                <StackPanel x:Name="Item3Input" Visibility="Collapsed">

                    <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap">
 You can add accessibility support to your custom controls by creation Automation peers. In the demonstration below, a custom media control includes support for the Toggle and RangeValue patterns, which enable Automation clients to play or pause the video and change the current playback position.

                    </TextBlock>

                    <TextBlock Style="{StaticResource DescriptionTextStyle}" TextWrapping="Wrap" Margin="0,20,0,0" Text=""/>

                </StackPanel>

              </StackPanel>

            </StackPanel>

          </StackPanel>   

            <!-- Output section -->

          <TextBlock Text="Output" Margin="0,25,0,20" Style="{StaticResource H2Style}"/>

          <StackPanel x:Name="Output"  HorizontalAlignment="Left">

             <!-- Item 1-->

            <Grid x:Name="Item1Output" Width="450" HorizontalAlignment="Left">

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*"/>

                    <ColumnDefinition Width="250"/>

                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>

                    <RowDefinition/>

                    <RowDefinition/>

                    <RowDefinition/>

                    <RowDefinition/>

                    <RowDefinition/>

                </Grid.RowDefinitions>

   <TextBlock Text="Contact form" FontWeight="Bold" Style="{StaticResource DescriptionTextStyle}" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" />
   <TextBlock x:Name="tbFrom" Text="From:" FontWeight="Bold" Style="{StaticResource DescriptionTextStyle}" Grid.Column="0" Grid.Row="1" Margin="5" />

                 <TextBox Width="200" Grid.Column="1" Grid.Row="1" Margin="5" AutomationProperties.Name="From" />

                <TextBlock Text="To:" FontWeight="Bold" Style="{StaticResource DescriptionTextStyle}" Grid.Column="0" Grid.Row="2" Margin="5"/>

                <TextBox Width="200" Grid.Column="1" Grid.Row="2" Margin="5"  AutomationProperties.Name="To" />

                <TextBlock Text="Feedback:" FontWeight="Bold" Style="{StaticResource DescriptionTextStyle}" Grid.Column="0" Grid.Row="3" Margin="5"/>

                <TextBox Width="200" Grid.Column="1" Grid.Row="3" Margin="5"  AutomationProperties.Name="Feedback"/>

<Button Content="Submit" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" Grid.Row="4" Margin="5"AutomationProperties.HelpText="Click to submit contact form"/>

            </Grid>

            <!-- Item 2 -->

            <StackPanel x:Name="Item2Output" >

                <Border BorderBrush="LightBlue" BorderThickness="4" CornerRadius="4">

                    <StackPanel Margin="5">

                        <TextBlock Text="Custom tab sequence (click in the container then press TAB to test)" Style="{StaticResource DescriptionTextStyle}"/>

                        <Button Content="Second" TabIndex="2"/>

                        <Button Content="Skipped" IsTabStop="False"/>

                        <Button Content="First" TabIndex="1"/>

                        <Button Content="Default (receives focus later)"/>

                    </StackPanel>

                </Border>

            </StackPanel>

             <!-- Item 3 -->

            <StackPanel x:Name="Item3Output" >

            </StackPanel>

          </StackPanel>

        </StackPanel>

      </ScrollViewer>

     </StackPanel>

    </Grid>

  </Grid>

</UserControl>

Step 4 : After running this code we get the following output. We have to create an accessible data entry form by automation setting properties on form elements.

output1.gif

In the tab sequence the tab key will cycle through controls in the order they are declared in XAML.

output2.gif

Here we can add accessibilty support to your custom controls by creation of automation peers.

output3.gif