NavigationPaneFilter

protected override void Run(IUITestActionStack stack)
{
    // If it has any children, this is just an organizational
    // TreeItem, so we can ignore that action.
    if (Playback
        .GetCoreTechnologyManager("MSAA")
        .GetChildren(stack.Peek().UIElement, null)
        .MoveNext())
    {
        stack.Pop();
        return;
    }

    UITestAction action = stack.Peek();

    UITechnologyElement toolbar = GetToolbar(action);

    var mouse = new MouseAction(toolbar,
        System.Windows.Forms.MouseButtons.Left,
        MouseActionType.Click);
    // The farthest right location on the toolbar.
    mouse.Location = new System.Drawing.Point(835, 5);
    var keys = new SendKeysAction();
    keys.Text = "USMF" + PathRepresented(action.UIElement) + "{Enter}";
    stack.Pop();
    // If the user set the area page the newly pushed actions will do that anyway.
    if (stack.Count >= 2 &&
        stack.Peek(1).UIElement.ControlTypeName == "SplitButton")
    {
        stack.Pop();
        stack.Pop();
    }
    stack.Push(mouse);
    stack.Push(keys);
}

This filter is one of the two large filters, and does a fair amount of fiddling with the UI hierarchy. The purpose is to optimize navigation using the navigation pane on the left side of the AX main frame.

The run method handles creating actions which will click on the navigation bar, and type in the destination. There is a trick here I use elsewhere, in which I don't pass a UITechnologyElement to the SendKeysAction. The empty constructor is only supposed to be used by the XML serializer, but it allows us to create a SendKeysAction which doesn't target a specific control. The action instead sends the key presses to the global windows event handler. This can speed things up, and allows us to type in controls that would otherwise be unfindable.

private UITechnologyElement GetToolbar(UITestAction action)
{
    AXUtils.Manager = Playback.GetCoreTechnologyManager("UIA");
    IUITechnologyElement parent = AXUtils.Desktop
        .Child("Dynamics", "Window")
        .Child("WindowHeaderFrame", "Pane")
        .Child("Pane")
        .Child("TopRow", "Pane")
        .Child("AddressBarContainer", "Pane");

    IUITechnologyElement toolbar = parent.Child("ToolBar");

    toolbar.QueryId.Ancestor = new UITechnologyElementRedirect(parent,
        action.UIElement.TopLevelElement,
        Playback.GetCoreTechnologyManager("MSAA"), "MSAA");
    toolbar.QueryId.Condition = new AndCondition(
        new PropertyCondition("ControlType", "ToolBar"));
    parent.QueryId.Condition = new AndCondition(
        new PropertyCondition("ClassName", "WindowsForms10.Window", PropertyConditionOperator.Contains),
        new PropertyCondition("Instance", "35"),
        new PropertyCondition("ControlType", "Window"));
    return new UITechnologyElementRedirect(toolbar,
        action.UIElement.TopLevelElement,
        Playback.GetCoreTechnologyManager("MSAA"), "MSAA");
}

This finds the navigation toolbar so that we can click on it during playback. The reason this is so awkward is that the extension technology is extremely close to the UI automation metal, making it difficult to navigate the UI hierarchy. The AXUtils helpers help a great deal with this, as you can see. In the end, I change the QueryId to represent known search parameters for the toolbar.

Last edited Aug 1, 2014 at 6:25 PM by wgoodin, version 9