自动化UI - 自定义控件不会显示

时间:2014-02-10 10:05:09

标签: c# automation

我在自动化UI方面遇到了问题。 我有一个有效的代码,但很难调试 - 所以我创建了一个应该更舒服的代码,但在一种情况下,它将无法工作 - 这种情况下是一个自定义控件。

我无法弄清楚为什么一个代码可以工作,而另一个代码则不行! 我尝试了很多方法并在网上搜索(许多类似的东西,但对我来说还不够好)

这是有效的代码:

    class ElementUtils
{

    public ElementUtils()
    {

    }

    public AutomationElement FindObjectFullPath(string parent, string childElements, string controlType)
    {
        string[] strElements = null;
        if (!string.IsNullOrEmpty(childElements))
        {
            childElements = childElements.Trim();

            strElements = childElements.Split(new string[] { "[", "]" }, StringSplitOptions.RemoveEmptyEntries);

            if (string.IsNullOrEmpty(parent) && !(childElements.StartsWith("[") && childElements.EndsWith("]")))
                throw new Exception("parent element and child elements are all empty. this input cannot be processed!");

            if (string.IsNullOrEmpty(parent))
                parent = strElements[0];

        }

        AutomationElement e = null;

        AutomationElementCollection desktop = GetDesktopElements();
        e = FindElement(desktop, parent);
        if (e == null)
        {
            return null;
        }

        AutomationElement ae = e;
        if (strElements != null) // ignore parent if you have full path element format
            ae = LocateElement(strElements, e, controlType);

        if (ae != null)
        {
            string fullPath = BuildElementFullNameForTest(ae);
            return ae;
        }
        return null;
    }

    private AutomationElement LocateElement(string[] elements, AutomationElement ae, string controlType)
    {
        AutomationElement e = ae;
        List<AutomationElement> eList = new List<AutomationElement>();
        List<AutomationElement> newElemList = new List<AutomationElement>();
        eList.Add(e);

        for (int i = 0; i < elements.Length; i++)
        {
            if (elements[i] == "null")
                continue;

            if (elements[i] == "empty")
                elements[i] = "";

            newElemList.Clear();
            newElemList.AddRange(eList);
            eList.Clear();

            foreach (AutomationElement ee in newElemList)
            {
                AutomationElementCollection c = GetObjectElements(ee);

                bool exactMatch = false;

                if (elements[i].StartsWith("#") && elements[i].EndsWith("#"))
                {
                    elements[i] = elements[i].Substring(1, elements[i].Length - 2);
                    exactMatch = true;
                }

                if (i == elements.Length - 1 && !controlType.Equals("IGNORE") && !controlType.Equals(""))
                {
                    eList.AddRange(FindAllSubElements(c, elements[i], StringToControlType(controlType), exactMatch));
                }
                else
                {
                    eList.AddRange(FindAllSubElements(c, elements[i], null, exactMatch));
                }
            }
        }

        if (eList.Count == 0)
            return null;
        return eList[0];
    }

    private List<AutomationElement> FindAllSubElements(AutomationElementCollection c, string ae, ControlType controlType, bool exactMatch)
    {
        List<AutomationElement> eList = new List<AutomationElement>();

        bool found = false;

        for (int i = 0; i < c.Count; i++)
        {
            // name should be exactly as expected element name
            if (exactMatch)
            {
                if (c[i].Current.Name.Equals(ae))
                    found = true;
            }
            else if (c[i].Current.Name.Contains(ae)) // name should be contained in expected element name
            {
                found = true;
            }

            if (found)
            {
                found = false;
                if (controlType != null)
                {
                    if (c[i].Current.ControlType.CompareTo(controlType) == 0)
                    {
                        eList.Add(c[i]);
                    }
                }
                else
                {
                    eList.Add(c[i]);
                }
            }

        }
        return eList;
    }

    public AutomationElementCollection GetDesktopElements()
    {
        return AutomationElement.RootElement.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
    }

    public AutomationElementCollection GetObjectElements(AutomationElement e)
    {
        return e.FindAll(TreeScope.Subtree, System.Windows.Automation.Condition.TrueCondition);
    }

    private AutomationElement FindElement(AutomationElementCollection c, string name)
    {
        for (int i = 0; i < c.Count; i++)
        {
            if (c[i].Current.Name.Contains(name))
            {
                return c[i];
            }
        }
        return null;
    }

    private AutomationElement FindElement(AutomationElementCollection c, string name, ControlType controlType)
    {
        for (int i = 0; i < c.Count; i++)
        {
            if (c[i].Current.Name.Contains(name) && c[i].Current.ControlType.CompareTo(controlType) == 0)
                return c[i];
        }
        return null;
    }

    private AutomationElement FindElement(List<AutomationElement> elements, string name)
    {
        foreach (AutomationElement e in elements)
        {
            if (e.Current.Name.Contains(name))
                return e;
        }
        return null;
    }

    private string BuildElementFullNameForTest(AutomationElement element)
    {
        TreeWalker walker = TreeWalker.ControlViewWalker;
        AutomationElement elementParent;
        AutomationElement node = element;

        if (element == null)
        {
            return null;
        }

        string elementFullName = element.Current.Name + "]";

        do
        {
            elementParent = walker.GetParent(node);
            if (elementParent == AutomationElement.RootElement)
                break;
            if (!elementParent.Current.Name.Equals(""))
                elementFullName = elementParent.Current.Name + "][" + elementFullName;
            node = elementParent;
        }
        while (true);

        return "[" + elementFullName;
    }

    private void WalkAllElements(AutomationElement rootElement, List<AutomationElement> collection)
    {
        TreeWalker walker = TreeWalker.ControlViewWalker;
        AutomationElement e = walker.GetFirstChild(rootElement);
        while (e != null)
        {
            collection.Add(e);
            WalkAllElements(e, collection);
            e = walker.GetNextSibling(e);
        }
    }


    private ControlType StringToControlType(string controlType)
    {
        switch (controlType)
        {
            case "Button":
                return ControlType.Button;
            case "Calendar":
                return ControlType.Calendar;
            case "CheckBox":
                return ControlType.CheckBox;
            case "ComboBox":
                return ControlType.ComboBox;
            case "DataGrid":
                return ControlType.DataGrid;
            case "DataItem":
                return ControlType.DataItem;
            case "Document":
                return ControlType.Document;
            case "Edit":
                return ControlType.Edit;
            case "Group":
                return ControlType.Group;
            case "Header":
                return ControlType.Header;
            case "HeaderItem":
                return ControlType.HeaderItem;
            case "Hyperlink":
                return ControlType.Hyperlink;
            case "Image":
                return ControlType.Image;
            case "List":
                return ControlType.List;
            case "ListItem":
                return ControlType.ListItem;
            case "Menu":
                return ControlType.Menu;
            case "MenuBar":
                return ControlType.MenuBar;
            case "MenuItem":
                return ControlType.MenuItem;
            case "Pane":
                return ControlType.Pane;
            case "ProgressBar":
                return ControlType.ProgressBar;
            case "RadioButton":
                return ControlType.RadioButton;
            case "ScrollBar":
                return ControlType.ScrollBar;
            case "Separator":
                return ControlType.Separator;
            case "Slider":
                return ControlType.Slider;
            case "Spinner":
                return ControlType.Spinner;
            case "SplitButton":
                return ControlType.SplitButton;
            case "StatusBar":
                return ControlType.StatusBar;
            case "Tab":
                return ControlType.Tab;
            case "TabItem":
                return ControlType.TabItem;
            case "Table":
                return ControlType.Table;
            case "Text":
                return ControlType.Text;
            case "Thumb":
                return ControlType.Thumb;
            case "TitleBar":
                return ControlType.TitleBar;
            case "ToolBar":
                return ControlType.ToolBar;
            case "ToolTip":
                return ControlType.ToolTip;
            case "Tree":
                return ControlType.Tree;
            case "TreeItem":
                return ControlType.TreeItem;
            case "Window":
                return ControlType.Window;
            default:
                return null;
        }
    }

}

这是不会的代码:

    class ElementUtils
{
    static TestLog tl;
    static TestLog ofl = new TestLog("ObjectFinderLog.txt", true);

    public ElementUtils(TestLog testLog)
    {
        tl = testLog;
    }

    private ControlType StringToControlType(string controlType)
    {
        switch (controlType)
        {
            case "Button":
                return ControlType.Button;
            case "Calendar":
                return ControlType.Calendar;
            case "CheckBox":
                return ControlType.CheckBox;
            case "ComboBox":
                return ControlType.ComboBox;
            case "DataGrid":
                return ControlType.DataGrid;
            case "DataItem":
                return ControlType.DataItem;
            case "Document":
                return ControlType.Document;
            case "Edit":
                return ControlType.Edit;
            case "Group":
                return ControlType.Group;
            case "Header":
                return ControlType.Header;
            case "HeaderItem":
                return ControlType.HeaderItem;
            case "Hyperlink":
                return ControlType.Hyperlink;
            case "Image":
                return ControlType.Image;
            case "List":
                return ControlType.List;
            case "ListItem":
                return ControlType.ListItem;
            case "Menu":
                return ControlType.Menu;
            case "MenuBar":
                return ControlType.MenuBar;
            case "MenuItem":
                return ControlType.MenuItem;
            case "Pane":
                return ControlType.Pane;
            case "ProgressBar":
                return ControlType.ProgressBar;
            case "RadioButton":
                return ControlType.RadioButton;
            case "ScrollBar":
                return ControlType.ScrollBar;
            case "Separator":
                return ControlType.Separator;
            case "Slider":
                return ControlType.Slider;
            case "Spinner":
                return ControlType.Spinner;
            case "SplitButton":
                return ControlType.SplitButton;
            case "StatusBar":
                return ControlType.StatusBar;
            case "Tab":
                return ControlType.Tab;
            case "TabItem":
                return ControlType.TabItem;
            case "Table":
                return ControlType.Table;
            case "Text":
                return ControlType.Text;
            case "Thumb":
                return ControlType.Thumb;
            case "TitleBar":
                return ControlType.TitleBar;
            case "ToolBar":
                return ControlType.ToolBar;
            case "ToolTip":
                return ControlType.ToolTip;
            case "Tree":
                return ControlType.Tree;
            case "TreeItem":
                return ControlType.TreeItem;
            case "Window":
                return ControlType.Window;
            default:
                return null;
        }
    }

    public AutomationElement FindObjectFullPath(string parent, string childElements, string controlType)
    {
        string[] strElements = null;

        if (!string.IsNullOrEmpty(childElements))
        {
            childElements = childElements.Trim();
            strElements = childElements.Split(new string[] { "[", "]" }, StringSplitOptions.RemoveEmptyEntries);

            if (string.IsNullOrEmpty(parent) && !(childElements.StartsWith("[") && childElements.EndsWith("]")))
            {
                throw new Exception("parent element and child elements are all empty. this input cannot be processed!");
            }
            if (string.IsNullOrEmpty(parent))
                parent = strElements[0];

        }

        AutomationElement parentAutomationElement = null;
        AutomationElementCollection desktop = GetDesktopElements();
        parentAutomationElement = FindElement(desktop, parent);
        if (parentAutomationElement == null)
        {
            return null;
        }

        //Generate object list
        ObjectFinderElement root = new ObjectFinderElement(parentAutomationElement, ofl);
        root.PrintToLog("\n\nLog for object path " + childElements);
        root.PrintToLog("\n" + root.PrintTree());

        return LocateElement(strElements, root, controlType);
    }

    public AutomationElementCollection GetDesktopElements()
    {
        return AutomationElement.RootElement.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
    }

    private AutomationElement FindElement(AutomationElementCollection c, string name)
    {
        for (int i = 0; i < c.Count; i++)
        {
            if (c[i].Current.Name.Contains(name))
            {
                return c[i];
            }
        }
        return null;
    }

    private AutomationElement LocateElement(string[] elements, ObjectFinderElement root, string controlType)
    {
        ObjectFinderElement objectPath = root;
        String foundPath = "";
        if (elements == null)
            return objectPath.GetAutomationElement();

        for (int i = 0; i < elements.Length; i++)
        {
            if (elements[i] == "null")
                continue;

            if (elements[i] == "empty")
                elements[i] = "";

            foundPath += "[" + elements[i] + "]";
            Boolean exactMatch = false;

            if (elements[i].StartsWith("#") && elements[i].EndsWith("#"))
            {
                elements[i] = elements[i].Substring(1, elements[i].Length - 2);
                exactMatch = true;
            }

            ControlType ct = null;

            if (i == elements.Length - 1 && !controlType.Equals("IGNORE") && !controlType.Equals(""))
            {
                ct = StringToControlType(controlType);
            }

            objectPath = objectPath.FindObjectFinderElement(elements[i], exactMatch, ct);

            if (objectPath == null)
            {
                tl.AddLine("Error: FindObjectFullPath - Object path '" + foundPath + "' could not be found");
                return null;
            }
        }

        tl.AddLine("Success: FindObjectFullPath: Object path " + foundPath + " was found successfully!");
        return objectPath.GetAutomationElement();
    }

}

class ObjectFinderElement
{
    private AutomationElement current;
    private List<ObjectFinderElement> children = new List<ObjectFinderElement>();
    private static TestLog ofl;

    public ObjectFinderElement(AutomationElement current, TestLog testlog)
    {
        ofl = testlog;
        this.current = current;
        AutomationElementCollection childrenTemp = current.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
        children.Capacity = childrenTemp.Count;
        foreach (AutomationElement child in childrenTemp)
            children.Add(new ObjectFinderElement(child, ofl));
    }

    public String PrintTree()
    {
        return PrintTree("");
    }

    public String PrintTree(String preText)
    {
        String self = preText + GetExtendedInfo();

        foreach (ObjectFinderElement child in children)
            self += "\n" + child.PrintTree("   |" + preText);

        return self;
    }

    public ObjectFinderElement FindObjectFinderElement(String name)
    {
        return FindObjectFinderElement(name, false, null);
    }

    public ObjectFinderElement FindObjectFinderElement(String name, Boolean exactMatch)
    {
        return FindObjectFinderElement(name, exactMatch, null);
    }

    public ObjectFinderElement FindObjectFinderElement(String name, Boolean exactMatch, ControlType controlType)
    {
        String ct = "IGNORE";
        if (controlType != null)
            ct = controlType.LocalizedControlType.ToString();

        ofl.AddLine("Scanning for \"" + name + "\" - Exact Match: " + exactMatch + " Control Type: " + ct);

        ObjectFinderElement res = FindObjectFinderElementIMP(name, exactMatch, controlType);
        if (res != null)
        {
            ofl.AddLine("Found element \"" + res.GetName() + "\"");
        }
        return res;
    }

    public ObjectFinderElement FindObjectFinderElementIMP(String name, Boolean exactMatch, ControlType controlType)
    {
        ObjectFinderElement res = null;
        ofl.AddLine("Scanning element \"" + current.Current.Name + "\"");
        Boolean found = CompareElements(name, exactMatch, controlType);

        if (found)
            res = this;
        else
        {
            foreach (ObjectFinderElement child in children)
            {
                res = child;
                if (res.CompareElements(name, exactMatch, controlType))
                    return res;
            }
            foreach (ObjectFinderElement child in children)
            {
                res = child.FindObjectFinderElementIMP(name, exactMatch, controlType);
                if (res != null)
                {
                    found = true;
                    break;
                }
            }
        }
        if (found)
            return res;
        return null;
    }

    private Boolean CompareElements(String name, Boolean exactMatch, ControlType controlType)
    {
        Boolean found = false;
        // name should be exactly as expected element name
        if (exactMatch)
        {
            if (current.Current.Name.Equals(name))
                found = true;
        }
        //name should be contained in expected element name
        else if (current.Current.Name.Contains(name))
        {
            found = true;
        }
        //Test for control type, if needed
        if (found == true && controlType != null)
        {
            if (current.Current.ControlType.CompareTo(controlType) != 0)
                found = false;
        }

        return found;
    }

    public AutomationElement GetAutomationElement()
    {
        return current;
    }

    public String GetName()
    {
        return current.Current.Name;
    }

    public String GetExtendedInfo()
    {
        return "\"" + current.Current.Name + "\" - " + current.Current.ControlType.LocalizedControlType + " - " + children.Count + " Children";
    }

    public String GetFullInfo()
    {
        return "Name: \"" + current.Current.Name + "\" - Localized Control Type: " + current.Current.ControlType.LocalizedControlType + " - Bounding Rectangle: " + current.Current.BoundingRectangle + " - Is Content Element: " + current.Current.IsContentElement + " - Is Control Element: " + current.Current.IsControlElement + " - Is Enabled: " + current.Current.IsEnabled + " - Is Keyboard Focusable: " + current.Current.IsKeyboardFocusable + " - Is Offscreen: " + current.Current.IsOffscreen;
    }

    public void PrintToLog(String text)
    {
        ofl.AddLine(text);
    }
}

我尝试过更改为树木步行者(原始),正如人们在这里建议的那样。不工作。 我还尝试更改ObjectFinderElement(坏名称,我知道,WIP - 它首先有一个不同的目标 - 仅打印找到的元素的树)来搜索后代而不是子项,甚至是整个子树,但它不起作用。

我会试着通过解释我想要做的事情来使事情更清楚。 在Outlook 2010中,左侧边栏包含文件夹名称。我想达到它。 完整路径(使用Inspect)如下: [Microsoft Outlook] [NUIDocumentWindow] [空字符串] [空字符串] [空字符串] [文件夹列表] [Outlook电子邮件地址] [收件箱]

现在我发现它的问题是,第二个“空字符串”是“自定义控件”类型 - 当我打印元素树时 - 它不会在那里,同样适用于它自己的孩子(我需要)。

然而,使用其他方法(第一个代码段)它似乎找到 - 即使我无法打印树,它确实发送鼠标点击它(代码段不包括实际的自动化)。 / p>

由此,我总结了问题出现的地方 - 元素搜索。 在第一个代码段中,如下所示:

public AutomationElementCollection GetObjectElements(AutomationElement e)
    {
        return e.FindAll(TreeScope.Subtree, System.Windows.Automation.Condition.TrueCondition);
    }

在第二个代码段中,元素树的填充代码是;

public ObjectFinderElement(AutomationElement current, TestLog testlog)
    {
        ofl = testlog;
        this.current = current;
        AutomationElementCollection childrenTemp = current.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
        children.Capacity = childrenTemp.Count;
        foreach (AutomationElement child in childrenTemp)
            children.Add(new ObjectFinderElement(child, ofl));
    }

所以我认为这是树木镜。但即使(出于测试目的)我将范围更改为子树(使列表变得疯狂并且具有多个元素) - 缺少的元素仍然不存在!

我会发布下面收到的树(当然还有treecope = Children):

2/10/2014 11:55:55 AM - 

Log for object path [Folder List][Contacts]
2/10/2014 11:55:55 AM - 
"Inbox - test320@****.com - Microsoft Outlook" - window - 11 Children
   |"Frame Splitter" - pane - 0 Children
   |"Frame Splitter" - pane - 0 Children
   |"MsoDockTop" - pane - 1 Children
   |   |"Ribbon" - pane - 1 Children
   |   |   |"Ribbon" - pane - 1 Children
   |   |   |   |"" - pane - 1 Children
   |   |   |   |   |"" - pane - 0 Children
   |"MsoDockBottom" - pane - 1 Children
   |   |"Status Bar" - pane - 1 Children
   |   |   |"Status Bar" - pane - 1 Children
   |   |   |   |"" - pane - 1 Children
   |   |   |   |   |"" - pane - 0 Children
   |"" - pane - 0 Children
   |"FolderBar" - pane - 1 Children
   |   |"NUIDocumentWindow" - pane - 1 Children
   |   |   |"" - pane - 1 Children
   |   |   |   |"" - pane - 1 Children
   |   |   |   |   |"" - pane - 0 Children
   |"NUIDocumentWindow" - pane - 1 Children
   |   |"" - pane - 0 Children
   |"NUIDocumentWindow" - pane - 1 Children
   |   |"" - pane - 0 Children
   |"" - pane - 2 Children
   |   |"" - pane - 1 Children
   |   |   |"" - pane - 13 Children
   |   |   |   |"DAL=on" - tool bar - 0 Children
   |   |   |   |"" - text - 0 Children
   |   |   |   |"TestAppointment" - pane - 0 Children
   |   |   |   |"" - pane - 0 Children
   |   |   |   |"" - pane - 0 Children
   |   |   |   |"Required: " - pane - 0 Children
   |   |   |   |"" - pane - 0 Children
   |   |   |   |"When:" - pane - 0 Children
   |   |   |   |"Saturday, June 04, 2016 8:00 AM-8:30 AM" - pane - 0 Children
   |   |   |   |"Location:" - pane - 0 Children
   |   |   |   |"None" - pane - 0 Children
   |   |   |   |"" - pane - 2 Children
   |   |   |   |   |"Vertical" - pane - 1 Children
   |   |   |   |   |   |"" - pane - 0 Children
   |   |   |   |   |"Day View" - pane - 0 Children
   |   |   |   |"" - pane - 1 Children
   |   |   |   |   |"" - pane - 2 Children
   |   |   |   |   |   |"Message" - pane - 0 Children
   |   |   |   |   |   |"Vertical" - pane - 1 Children
   |   |   |   |   |   |   |"" - pane - 0 Children
   |   |"Microsoft Outlook Social Connector" - pane - 2 Children
   |   |   |"" - pane - 0 Children
   |   |   |"Click to expand the People Pane" - button - 0 Children
   |"Table View" - pane - 1 Children
   |   |"Vertical" - pane - 1 Children
   |   |   |"" - pane - 0 Children
   |"Inbox - test320@****.com - Microsoft Outlook" - title bar - 4 Children
   |   |"System Menu Bar" - menu bar - 1 Children
   |   |   |"System" - menu item - 0 Children
   |   |"Minimize" - button - 0 Children
   |   |"Restore" - button - 0 Children
   |   |"Close" - button - 0 Children

我想这是很多东西,但是非常感谢帮助。

更新: 我找到了另外一个提示 - 似乎为了找到所有元素,我需要使用“AutomationElement.RootElement.FindAll(TreeScope.Subtree,Sy​​stem.Windows.Automation.Condition.TrueCondition);”

所以我不能像树一样组织它!这太麻烦了......

PS。我很难将文字发布为代码...

1 个答案:

答案 0 :(得分:0)

我已经解决了。我不知道怎么样,我暂时放弃它,所以我从头开始快速重写。 3-4分钟后,它的工作原理。

以下是感兴趣的人的代码;

using AutomationUtils;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Automation;

namespace GenericUIAutomation
{
class ElementTree
{
    private AutomationElement current;
    private List<ElementTree> children = new List<ElementTree>();
    private List<String> ancestorNames = new List<String>();
    private static TestLog ofl;

    public ElementTree(TestLog testlog)
    {
        ofl = testlog;
        this.current = AutomationElement.RootElement;
        //This is the root element, no ancestors.
        ancestorNames = null;
        AutomationElementCollection childrenTemp = current.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
        children.Capacity = childrenTemp.Count;

        List<String> childrenAncestors = new List<String>();
        childrenAncestors.Add(this.current.Current.Name);

        foreach (AutomationElement child in childrenTemp)
            children.Add(new ElementTree(child, childrenAncestors));

        childrenTemp = null;
    }

    public ElementTree(AutomationElement current, List<String> ancestorList)
    {
        this.current = current;
        this.ancestorNames = ancestorList;
        AutomationElementCollection childrenTemp = current.FindAll(TreeScope.Children, System.Windows.Automation.Condition.TrueCondition);
        children.Capacity = childrenTemp.Count;

        List<String> childrenAncestors = new List<String>();
        childrenAncestors.AddRange(ancestorList);
        childrenAncestors.Add(this.current.Current.Name);

        foreach (AutomationElement child in childrenTemp)
            children.Add(new ElementTree(child, childrenAncestors));

        childrenTemp = null;
    }

    public ElementTree FindInTree(String name, ControlType controlType, String[] ancestorList)
    {
        String ct = "IGNORE";
        if (controlType != null)
            ct = controlType.LocalizedControlType.ToString();

        ofl.AddLine("Scanning for \"" + name + "\" - " + " Control Type: " + ct);

        ElementTree res = FindInTreeIMP(name, controlType, ancestorList);
        if (res != null)
            ofl.AddLine("Success! Found element \"" + res.GetName() + "\" - " + res.GetAutomationElement().Current.ControlType.LocalizedControlType);
        else
            ofl.AddLine("Error! No matching element found.");
        return res;
    }

    public ElementTree FindInTreeIMP(String name, ControlType controlType, String[] ancestorList)
    {
        ofl.AddLine("Scanning element \"" + current.Current.Name + "\" - " + current.Current.ControlType.LocalizedControlType);
        Boolean found = CompareElements(name, controlType, ancestorList);

        if (found)
            return this;

        foreach (ElementTree child in children)
        {
            ElementTree res = child.FindInTreeIMP(name, controlType, ancestorList);
            if (res != null)
                return res;
        }

        return null;
    }

    private Boolean CompareElements(String name, ControlType controlType, String[] ancestorList)
    {
        Boolean found = false;

        //name should be contained in expected element name
        if (this.current.Current.Name.Contains(name))
        {
            PrintToLog("Name match found");
            found = true;
        }
        //Test for control type, if needed
        if (found == true && controlType != null)
        {
            PrintToLog("Control Type match found");
            if (this.current.Current.ControlType.CompareTo(controlType) != 0)
                found = false;
        }
        if (found == true && this.ancestorNames.Count >= ancestorList.Length)
        {
            PrintToLog("Searching for Ancestors");
            found = CheckAncestors(ancestorList);
        }
        else
            found = false;

        return found;
    }

    private Boolean CheckAncestors(String[] ancestorList)
    {
        Boolean found = false;
        foreach (String ancestorName in ancestorList)
        {
            PrintToLog("Scanning for ancestor " + ancestorName);
            foreach (String ancestorListElement in ancestorList)
                if (ancestorListElement.Contains(ancestorName))
                {
                    PrintToLog("Found ancestor " + ancestorListElement);
                    found = true;
                    break;
                }
            if (found != true)
                return found;
            else
                continue;

        }
        return found;
    }

    public String PrintTree()
    {
        return "\n" + PrintTree("");
    }

    public String PrintTree(String preText)
    {
        String self = preText + GetExtendedInfo();

        foreach (ElementTree child in children)
            self += "\n" + preText + child.PrintTree(preText + "   |");
        return self;
    }

    public AutomationElement GetAutomationElement()
    {
        return current;
    }

    public String GetName()
    {
        return current.Current.Name;
    }

    public String GetExtendedInfo()
    {
        int childrenCount = 0;
        int ancestorsCount = 0;
        String name = current.Current.Name;
        String controlType = current.Current.ControlType.LocalizedControlType;

        if (children != null)
            childrenCount = children.Count;
        if (ancestorNames != null)
            ancestorsCount = ancestorNames.Count;

        return "\"" + name + "\" - " + controlType + " - " + childrenCount + " Children" + " - " + ancestorsCount + " Ancestors";
    }

    public void PrintToLog(String text)
    {
        ofl.AddLine(text);
    }
}
}

还有工作要做,但......有效。