This documentation is archived and is not being maintained.

Expose the Content of a Table Using UI Automation

This topic shows how Microsoft UI Automation can be used to expose the content and intrinsic properties of each cell within a tabular control.

Example

The following code example demonstrates how to obtain an AutomationElement that represents the content of a table cell; cell properties such as row and column indices, row and column spans, and row and column header information are also obtained. This example uses a focus change event handler to simulate keyboard traversal of a tabular control that implements UI Automation. Information for each table item is exposed on a focus change event.

NoteNote:

Since focus changes are global desktop events, focus change events outside the table should be filtered. See the TrackFocus Sample for a related implementation.

    /// -------------------------------------------------------------------
    /// <summary>
    /// Starts the target application and returns the AutomationElement 
    /// obtained from the targets window handle.
    /// </summary>
    /// <param name="exe">
    /// The target application.
    /// </param>
    /// <param name="filename">
    /// The text file to be opened in the target application
    /// </param>
    /// <returns>
    /// An AutomationElement representing the target application.
    /// </returns>
    /// -------------------------------------------------------------------
    private AutomationElement StartTarget(string exe, string filename)
    {
        // Start text editor and load with a text file.
        Process p = Process.Start(exe, filename);

        // targetApp --> the root AutomationElement
        AutomationElement targetApp =
            AutomationElement.FromHandle(p.MainWindowHandle);

        return targetApp;
    }

...

    /// -------------------------------------------------------------------
    /// <summary>
    /// Obtain the table control of interest from the target application.
    /// </summary>
    /// <param name="targetApp">
    /// The target application.
    /// </param>
    /// <returns>
    /// An AutomationElement representing a table control.
    /// </returns>
    /// -------------------------------------------------------------------
    private AutomationElement GetTableElement(AutomationElement targetApp)
    {
        // The control type we're looking for; in this case 'Document'
        PropertyCondition cond1 =
            new PropertyCondition(
            AutomationElement.ControlTypeProperty,
            ControlType.Table);

        // The control pattern of interest; in this case 'TextPattern'.
        PropertyCondition cond2 =
            new PropertyCondition(
            AutomationElement.IsTablePatternAvailableProperty,
            true);

        AndCondition tableCondition = new AndCondition(cond1, cond2);

        AutomationElement targetTableElement =
            targetApp.FindFirst(TreeScope.Descendants, tableCondition);

        // If targetTableElement is null then a suitable table control 
        // was not found.
        return targetTableElement;
    }

...

    ///--------------------------------------------------------------------
    /// <summary>
    /// Obtains a TableItemPattern control pattern from an 
    /// AutomationElement.
    /// </summary>
    /// <param name="targetControl">
    /// The AutomationElement of interest.
    /// </param>
    /// <returns>
    /// A TableItemPattern object.
    /// </returns>
    ///--------------------------------------------------------------------
    private TableItemPattern GetTableItemPattern(
        AutomationElement targetControl)
    {
        TableItemPattern tableItemPattern = null;

        try
        {
            tableItemPattern =
                targetControl.GetCurrentPattern(
                TableItemPattern.Pattern)
                as TableItemPattern;
        }
        // Object doesn't support the 
        // TableItemPattern control pattern
        catch (InvalidOperationException)
        {
            return null;
        }

        return tableItemPattern;
    }

...

    ///--------------------------------------------------------------------
    /// <summary>
    /// Obtains a TablePattern control pattern from an 
    /// AutomationElement.
    /// </summary>
    /// <param name="targetControl">
    /// The AutomationElement of interest.
    /// </param>
    /// <returns>
    /// A TablePattern object.
    /// </returns>
    ///--------------------------------------------------------------------
    private TablePattern GetTablePattern(
        AutomationElement targetControl)
    {
        TablePattern tablePattern = null;

        try
        {
            tablePattern =
                targetControl.GetCurrentPattern(
                TablePattern.Pattern)
                as TablePattern;
        }
        // Object doesn't support the 
        // TablePattern control pattern
        catch (InvalidOperationException)
        {
            return null;
        }

        return tablePattern;
    }

...

    ///--------------------------------------------------------------------
    /// <summary>
    /// Set up table item event listeners.
    /// </summary>
    /// <remarks>
    /// The event listener is essentially a focus change listener.
    /// Since this is a global desktop listener, a filter would be required 
    /// to ignore focus change events outside the table.
    /// </remarks>
    ///--------------------------------------------------------------------
    private void SetTableItemEventListeners()
    {
        AutomationFocusChangedEventHandler tableItemFocusChangedListener =
            new AutomationFocusChangedEventHandler(OnTableItemFocusChange);
        Automation.AddAutomationFocusChangedEventHandler(
            tableItemFocusChangedListener);
    }

...

    ///--------------------------------------------------------------------
    /// <summary>
    /// Event handler for table item focus change.
    /// Can be used to track traversal of individual table items 
    /// within a table.
    /// </summary>
    /// <param name="src">Object that raised the event.</param>
    /// <param name="e">Event arguments.</param>
    ///--------------------------------------------------------------------
    private void OnTableItemFocusChange(
        object src, AutomationFocusChangedEventArgs e)
    {
        // Make sure the element still exists. Elements such as tooltips
        // can disappear before the event is processed.
        AutomationElement sourceElement;
        try
        {
            sourceElement = src as AutomationElement;
        }
        catch (ElementNotAvailableException)
        {
            return;
        }

        // Get a TableItemPattern from the source of the event.
        TableItemPattern tableItemPattern =
            GetTableItemPattern(sourceElement);

        if (tableItemPattern == null)
        {
            return;
        }

        // Get a TablePattern from the container of the current element.
        TablePattern tablePattern =
            GetTablePattern(tableItemPattern.Current.ContainingGrid);

        if (tablePattern == null)
        {
            return;
        }

        AutomationElement tableItem = null;
        try
        {
            tableItem = tablePattern.GetItem(
            tableItemPattern.Current.Row,
            tableItemPattern.Current.Column);
        }
        catch (ArgumentOutOfRangeException)
        {
            // If the requested row coordinate is larger than the RowCount 
            // or the column coordinate is larger than the ColumnCount.
            // -- OR --
            // If either of the requested row or column coordinates 
            // is less than zero.
            // TO DO: error handling.
        }

        // Further event processing can be done at this point.
        // For the purposes of this sample we can just record item properties.
        string controlType = 
            tableItem.Current.ControlType.LocalizedControlType;
        AutomationElement[] columnHeaders = 
            tableItemPattern.Current.GetColumnHeaderItems();
        AutomationElement[] rowHeaders = 
            tableItemPattern.Current.GetRowHeaderItems();
        int itemRow = tableItemPattern.Current.Row;
        int itemColumn = tableItemPattern.Current.Column;
        int itemRowSpan = tableItemPattern.Current.RowSpan;
        int itemColumnSpan = tableItemPattern.Current.ColumnSpan;
    }

    ///--------------------------------------------------------------------
    /// <summary>
    /// Handles the application shutdown.
    /// </summary>
    /// <param name="args">Event arguments.</param>
    ///--------------------------------------------------------------------
    protected override void OnExit(System.Windows.ExitEventArgs args)
    {
        Automation.RemoveAllEventHandlers();
        base.OnExit(args);
    }

See Also

Show: