AutomationPeer.GetChildrenCore () only reports first child to VisualStudio.TestTools

248 Views Asked by At

I'm not able to override GetChildrenCore correctly. I use this for a Canvas to get information about it's children (Line, Rectangle).

The output correctly indicates the first child but misses the second. Even though the Canvas already contains both.

Custom Canvas  
    Custom Line Childs of Canvas parent: 2  

Instead it should be like this:

Custom Canvas  
    Custom Line Childs of Canvas parent: 2  
    Custom Rectangle Childs of Canvas parent: 2  

App side side:

public class ElementAP : FrameworkElementAutomationPeer
{
    private FrameworkElement Owner = null;
    private Int32 Count = 0;

    public ElementAP(FrameworkElement owner, Int32 count) : base (owner)
    {
        Owner = owner;
        Count = count;
    }

    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Custom;
    }

    protected override string GetClassNameCore()
    {
        return $"{Owner.GetType().Name} Childs of Canvas parent: {Count}"; 
    }
}

public class CanvasAP : FrameworkElementAutomationPeer
{
    public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner)
    {
    }

    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Custom;
    }

    protected override string GetClassNameCore()
    {
        return "Canvas";
    }

    protected override IList<AutomationPeer> GetChildrenCore()
    {
        var owner = (Windows.UI.Xaml.Controls.Canvas)Owner;           
        var list = new List<AutomationPeer> ();

        foreach (var child in owner.Children)
        {
            var peer = new ElementAP(child as FrameworkElement, owner.Children.Count);

            list.Add(peer);
        }

        return list;
    }
}       

UI Testing side:

private static string WalkTree(UITestControl element, Int32 level = 0)
{
    var children = element.GetChildren();

    var str = "";
    foreach (var c in children)
    {
        str += GetElementString(c, level);
        str += WalkTree(c, level + 1);
    }

    return str;
}

private static string GetElementString(UITestControl element, Int32 level = 0)
{
    var xaml = element as XamlControl;
    var str = "";
    for (var i = 0; i < level; i++)
        str += "  ";

    str += $"{element.ControlType} {element.ClassName} {element.Name} {xaml?.AutomationId ?? ""}\n";

    return str;
}   
1

There are 1 best solutions below

0
On BEST ANSWER

I finally found an answer. When using a cache for the children`s AutomationPeers it works perfectly.

public class ElementAP : FrameworkElementAutomationPeer
{
    public UIElement Element { get { return Owner; } }

    public ElementAP(FrameworkElement owner) : base(owner)
    {
    }

    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Custom;
    }

    protected override string GetClassNameCore()
    {
        return Owner.GetType().Name;
    }
}

public class CanvasAP : FrameworkElementAutomationPeer
{
    private List<ElementAP> _cachedAutomationPeers = new List<ElementAP>();

    public CanvasAP(Windows.UI.Xaml.Controls.Canvas owner) : base(owner)
    {
    }

    protected override AutomationControlType GetAutomationControlTypeCore()
    {
        return AutomationControlType.Custom;
    }

    protected override string GetClassNameCore()
    {
        return "Canvas";
    }

    protected override IList<AutomationPeer> GetChildrenCore()
    {
        var owner = (Windows.UI.Xaml.Controls.Canvas)Owner;

        if (owner.Children.All(c => c is CanvasA))
            return base.GetChildrenCore();

        var list = new List<ElementAP>();

        foreach (var child in owner.Children)
        {
            var peer = _cachedAutomationPeers.FirstOrDefault(p => p.Element == child) ?? new ElementAP(child as FrameworkElement);

            list.Add(peer);
        }

        _cachedAutomationPeers = list;

        return list.Cast<AutomationPeer>().ToList();
    }
}