如何使用Microsoft UI自动化测试在Asp.Net页面上查找Silvlerlight对象?

如何使用Microsoft UI自动化测试在Asp.Net页面上查找Silvlerlight对象?,asp.net,silverlight-4.0,ui-automation,Asp.net,Silverlight 4.0,Ui Automation,我的asp.net页面上有一个对象,它承载着Silverlight xap(在我的特殊情况下,它位于IFrame中,但我对常规对象也很好奇)。我可以在UI Spy中找到该元素,但其名称只是说“Silverlight控件”。尝试在自动测试中查找AutomationElement失败(控件每次都为null)。Silverlight代码或html中是否有帮助的设置?如果同一页面上有多个Silverlight控件,我如何区分它 <object id="silverlightClient" styl

我的asp.net页面上有一个对象,它承载着Silverlight xap(在我的特殊情况下,它位于IFrame中,但我对常规对象也很好奇)。我可以在UI Spy中找到该元素,但其名称只是说“Silverlight控件”。尝试在自动测试中查找AutomationElement失败(控件每次都为null)。Silverlight代码或html中是否有帮助的设置?如果同一页面上有多个Silverlight控件,我如何区分它

<object id="silverlightClient" style="display:none;" data="data:application/x-silverlight-2," type="application/x-silverlight-2">
    <param name="source" value="../../ClientBin/SilverlightApplication.xap"/>
    <param name="onerror" value="onSilverlightError" />
    <param name="background" value="#00000000" /> 
    <param name="minRuntimeVersion" value="4.0.41019.0" />
    <param name="autoUpgrade" value="true" />
    <param name="windowless" value="false" />
</object>

   TreeWalker tw = new TreeWalker(new System.Windows.Automation.PropertyCondition(AutomationElement.NameProperty, "Silverlight Control));
   AutomationElement control = tw.GetFirstChild(ancestor);
编辑:添加了图像,我还意识到对象位于IFrame内部。

我创建了一些扩展方法,使使用AutomationElement变得更简单。我已经在下面粘贴了相关内容,但您可以阅读更多关于它们的内容

我假设你有根IE窗口的引用。如果不是,但您知道它是进程Id,您可以这样找到它:

var ieWindow = AutomationElement.RootElement.FindChildByCondition(new PropertyCondition(AutomationElement.ProcessIdProperty, ieProcessId));
假设IE中只有一个打开的框架,并且上面有一个Silverlight控件,那么您可以执行以下操作:

var silverlightControl = ieWindow.FindDescendentByClassPath(
                         new[]{
                               "Frame Tab",
                                 "TabWindowClass",
                                   "Shell DocObject View",
                                     "Internet Explorer_Server",
                                       "MicrosoftSilverlight",
                               });
如果您有多个Silverlight控件,我不知道如何通过UIAutomation来区分它们。我会尝试从上面的类路径中删除“MicrosoftSilverlight”条目,以便获得对资源管理器页面的引用。然后使用

AutomationElement.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "MicrosoftSilverlight"))
要查找所有SilverlightControls,请依次探测每个控件,并在其中找到允许您区分它们的元素

以下是扩展方法:

public static class AutomationExtensions
{
    public static AutomationElement FindDescendentByClassPath(this AutomationElement element, IEnumerable<string> classNames)
    {
        var conditionPath = CreateClassNameConditionPath(classNames);

        return element.FindDescendentByConditionPath(conditionPath);
    }

    public static AutomationElement FindDescendentByConditionPath(this AutomationElement element, IEnumerable<Condition> conditionPath)
    {
        if (!conditionPath.Any())
        {
            return element;
        }

        var result = conditionPath.Aggregate(
            element,
            (parentElement, nextCondition) => parentElement == null
                                                  ? null
                                                  : parentElement.FindChildByCondition(nextCondition));

        return result;
    }

    public static AutomationElement FindChildByCondition(this AutomationElement element, Condition condition)
    {
        var result = element.FindFirst(
            TreeScope.Children,
            condition);

        return result;
    }

    public static IEnumerable<Condition> CreateClassNameConditionPath(IEnumerable<string> classNames)
    {
        return classNames.Select(name => new PropertyCondition(AutomationElement.ClassNameProperty, name, PropertyConditionFlags.IgnoreCase)).ToArray();
    }
}
公共静态类AutomationExtensions
{
公共静态AutomationElement FindDescentByClassPath(此AutomationElement元素,IEnumerable类名称)
{
var conditionPath=CreateClassNameConditionPath(类名称);
返回元素。FindDescentByConditionPath(conditionPath);
}
公共静态AutomationElement FindDescentByConditionPath(此AutomationElement元素,IEnumerable conditionPath)
{
如果(!conditionPath.Any())
{
返回元素;
}
var result=conditionPath.Aggregate(
元素,
(parentElement,nextCondition)=>parentElement==null
无效的
:parentElement.FindChildByCondition(nextCondition));
返回结果;
}
公共静态AutomationElement FindChildByCondition(此AutomationElement元素,条件)
{
var result=element.FindFirst(
树镜,孩子们,
条件);
返回结果;
}
公共静态IEnumerable CreateClassNameConditionPath(IEnumerable类名)
{
返回classNames.Select(name=>newPropertyCondition(AutomationElement.ClassNameProperty,name,PropertyConditionFlags.IgnoreCase)).ToArray();
}
}

您正在使用哪个浏览器?我只有Silverlight UIAutomation可以在Internet Explorer中工作。我正在使用IE8,兼容模式处于启用状态。我非常喜欢您创建的扩展方法。但是,当使用browser.FindDesByClassPath(new[]{“Frame Tab”})时,我得到了null;你知道为什么会这样吗?你能告诉我们UISpy中的树是什么样子吗?你能看到IE窗口的一个子类“Frame Tab”吗?我添加了一个屏幕截图的链接。我还意识到对象位于IFrame内部。谢谢你的帮助。@Kevin:看起来框架在UI自动化中发挥得不好。尝试一个实验。打开UISpy,并确保Ctrl-Click选择模式处于启用状态。然后按住Ctrl键单击框架内的图元。执行此操作时,UISpy无法找到该元素,它会在输出窗格中报告一个错误。如果是这样的话,我认为您唯一可以使用的方法是使用AutomationElement.FromPoint方法查找帧,然后从那里导航到Silverlight控件。
public static class AutomationExtensions
{
    public static AutomationElement FindDescendentByClassPath(this AutomationElement element, IEnumerable<string> classNames)
    {
        var conditionPath = CreateClassNameConditionPath(classNames);

        return element.FindDescendentByConditionPath(conditionPath);
    }

    public static AutomationElement FindDescendentByConditionPath(this AutomationElement element, IEnumerable<Condition> conditionPath)
    {
        if (!conditionPath.Any())
        {
            return element;
        }

        var result = conditionPath.Aggregate(
            element,
            (parentElement, nextCondition) => parentElement == null
                                                  ? null
                                                  : parentElement.FindChildByCondition(nextCondition));

        return result;
    }

    public static AutomationElement FindChildByCondition(this AutomationElement element, Condition condition)
    {
        var result = element.FindFirst(
            TreeScope.Children,
            condition);

        return result;
    }

    public static IEnumerable<Condition> CreateClassNameConditionPath(IEnumerable<string> classNames)
    {
        return classNames.Select(name => new PropertyCondition(AutomationElement.ClassNameProperty, name, PropertyConditionFlags.IgnoreCase)).ToArray();
    }
}