Accessible Data: Making your data available for all


Making sure your application is accessible for tools like screen readers is important and you should be aware of and follow the guidelines outlined in Accessibility Best Practices.


 


One place you should be mindful about accessibility is when you bind a control to data.  How you make your data accessible depends on how you store your data.  Consider the following example, which binds a ListBox to an ObservableCollection:


 


    public class Employee


    {


        string name;


        string type;


        string number;


 


        public Employee(string newName, string newType, string newNumber)


        {


            name = newName;


            type = newType;


            number = newNumber;


        }


 


        public string EmployeeName


        {


            set { name = value; }


            get { return name; }


 


        }


 


        public string Type


        {


            set { type = value; }


            get { return type; }


        }


 


        public string EmployeeNumber


        {


            set { number = value; }


            get { return number; }


        }


 


        public override string ToString()


        {


            return EmployeeName;


        }


    }


 


    public class EmployeeList : ObservableCollection<Employee>


    {


        public EmployeeList()


        {


 


            this.Add(new Employee(“Terry Adams”, “FTE”, “1”));


            this.Add(new Employee(“Claire O’Donnell”, “FTE”, “12345”));


            this.Add(new Employee(“Palle Peterson”, “FTE”, “5678”));


            this.Add(new Employee(“Amy E. Alberts”, “CSG”, “99222”));


            this.Add(new Employee(“Stefan Hesse”, “Vendor”, “-“));


        }


    }


 


 


<Page x:Class=ScreenReaderTest.Window1


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


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


    xmlns:src=clr-namespace:ScreenReaderTest


    >


  <StackPanel>


    <ListBox TextSearch.TextPath=Name >


      <!–ItemsSource is usually bound to a resource, but this


      is a shorcut for the example–>


      <ListBox.ItemsSource>


        <src:EmployeeList/>


      </ListBox.ItemsSource>


    </ListBox>


  </StackPanel>


</Page>


 


The ListBox displays the string returned By Employee.ToString. Accessibility tools such as Microsoft Narrator also uses the value of ToString of the selected item to read it to the user. 


 


But there might be cases where the ToString method isn’t useful for screen readers.  For example, the XMLDataProvider class is an easy way to bind a control to data, but if you use this, you should realize that the default information provided to UI Automation is useless. The following example uses a XmlDataProvider to display the same information as the previous example.


 


<Page x:Class=ScreenReaderTest.Window1


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


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


    xmlns:src=clr-namespace:ScreenReaderTest


    >


  <Page.Resources>


    <XmlDataProvider x:Key=Employees XPath=/Employees/*>


      <x:XData>


        <Employees xmlns=“”>


          <Employee Name=Terry Adams


                    Type=FTE EmployeeNumber=1 />


          <Employee Name=Claire O&apos;Donnell


                    Type=FTE EmployeeNumber=12345 />


          <Employee Name=Palle Peterson


                    Type=FTE EmployeeNumber=5678 />


          <Employee Name=Amy E. Alberts


                    Type=CSG EmployeeNumber=99222 />


          <Employee Name=Stefan Hesse


                    Type=Vendor EmployeeNumber= />


        </Employees>


      </x:XData>


    </XmlDataProvider>


 


    <DataTemplate x:Key=EmployeeItemTemplate>


      <TextBlock Text={Binding XPath=@Name} />


    </DataTemplate>


 


  </Page.Resources>


 


  <StackPanel>


    <ListBox TextSearch.TextPath=@Name


             ItemTemplate={StaticResource EmployeeItemTemplate}


             ItemsSource={Binding Source={StaticResource Employees}} >


    </ListBox>


  </StackPanel>


</Page>


 


In this case, the DataTemplate called EmployeeItemTemplate determines what is displayed in the ListBox, but Narrator still uses the ToString method to get the value of each item in the ListBox, which is simply the string, “System.Xml.XmlElement”  To give something meaningful to Narrator, you can bind the AutomationProperties.Name property to the Employee.Name property.


 


    <ListBox ItemTemplate={StaticResource EmployeeItemTemplate}


             ItemsSource={Binding Source={StaticResource Employees}} >


      <ListBox.ItemContainerStyle>


        <Style>


          <Setter Property=AutomationProperties.Name


                  Value={Binding XPath=@Name}/>


        </Style>


      </ListBox.ItemContainerStyle>


    </ListBox>


 


Now Narrator will read exactly the same thing that is displayed in the ListBox.  The moral of the story is, if your data source doesn’t return an informative string in its ToString method, use the AutomationProperties.Name property to give something interesting to UI Automation.


Comments (3)

  1. xpwang_leo says:

    I have GridView include two column and the first colum is applied with dataTemplate which make up of one checkBox and TextBlock. The dataTemplate is not available When I applied the "DisplayMemberBinding" import the xml data. The first column only show the string and not show the checkBox. I post the the part of the code. Pls help thk!

         <ListView Name="CategoryList"Margin="16,59,39,35.9999999999999" IsSynchronizedWithCurrentItem="True" AllowDrop="false" ItemContainerStyle="{StaticResource MyContainerStyleKey}"  ItemsSource="{Binding Source={StaticResource ConfigData}, XPath=Song}" >

           <ListView.View>

             <GridView ColumnHeaderContainerStyle="{DynamicResource GridViewColumnHeaderStyle}">

               <GridViewColumn CellTemplate="{DynamicResource FileCategoryTemplate}" Header="{DynamicResource Archive_FileCategories}" Width="200" DisplayMemberBinding="{Binding XPath=@Category}" />

               <GridViewColumn CellTemplate="{DynamicResource FileExtensionTemplate}" Header="{DynamicResource Archive_FileExtensions}" Width="600" DisplayMemberBinding="{Binding XPath=@Extension}" />

             </GridView>

           </ListView.View>

         </ListView>

  2. wcsdkteam says:

    When you set the DisplayMemberBinding property, the GridViewColumn ignores the CellTemplate.  You should bind the data in the DataTemplate and omit the DisplayMemberBinding.

       <DataTemplate x:Key="FileCategoryTemplate">

         <CheckBox Content="{Binding XPath=@Category}"/>

       </DataTemplate>

    Hope that helps.

  3. I’ve been creating some WPF examples to hook up with my WCF applications by using Expression Blend I