如何扩展 CodedUI HtmlControls 并保留输入

How to extend CodedUI HtmlControls and preserve typing

我最近一直在深入研究 CodedUI,并且很高兴扩展库以包含其余 HTML 元素(无论出于何种原因)被排除在 Microsoft.VisualStudio.TestTools.UITesting.HtmlControls 之外命名空间。

我注意到我可以做如下事情:

var divs = new HtmlDiv(window).FindMatchingControls().OfType<HtmlDiv>();

这将 return 您所期望的:具有与 FindMatchingControls() 调用相同元素的 IEnumerable(只是键入 HtmlDiv 而不是 UITestControl)。

此外,我可以这样做:

public class HtmlHeader : HtmlCustom
{
    public static readonly string HeaderTag = "header";

    public HtmlHeader() : base() {
 this.SearchProperties.Add(HtmlControl.PropertyNames.TagName, HeaderTag, PropertyExpressionOperator.EqualTo);
    }
    public HtmlHeader(UITestControl parent) : base(parent) { 
     this.SearchProperties.Add(HtmlControl.PropertyNames.TagName, HeaderTag, PropertyExpressionOperator.EqualTo);
    }
}

甚至这个也有效:

var headerTag = new HeaderTag(window);

它将在屏幕上找到 header 个标签,并为您找到第一个标签。

var headerTags = new HeaderTag(window).FindMatchingControls();

工作正常,但是

var headerTags = new HeaderTag(window).FindMatchingControls().OfType<HeaderTag>();

为空。

为什么上述命名空间中的 HtmlControls 可以正确解析类型?

我能否利用隐式转换运算符/其他技巧将 OfType() 转换为 return 一个 collection HtmlTags?

我开始写这样的转换:

protected HeaderTag ConvertControl(HtmlControl toConvert)
    {
        if (StringComparer.OrdinalIgnoreCase(toConvert.TagName, "header"))
        {
            var ret = new HeaderTag();
            ret.SearchProperties.AddRange(toConvert.SearchProperties);
            ret.SearchConfigurations = toConvert.SearchConfigurations;
            ret.FilterProperties.AddRange(toConvert.FilterProperties);
            // screen element
            // technology is already set - web
            // cached queryid
            // cached parent
            // boundary screen element
            return ret;
        }
        throw new InvalidOperationException("Control cannot be converted.");
    }

但是,在反编译HtmlControl 类型本身之后,我看到有一个CopyFromControl 方法是不可访问的;此外,它设置的字段不可访问(上面已评论)。

我不确定我是否复制这些字段是否真的很重要,以及它们是否过于重要而无法复制,但我希望找到更好的解决方案。如果没有更好的办法出现,我可能会诉诸反思,但如果可以避免的话,我宁愿不走那条路。

UITestControl 基本上只是一个用于访问本机 UI 控件的包装器。一旦找到 UI 控件,UITestControl 就会保留对该对象的引用。然后您可以使用其 CopyFrom 函数复制该引用(连同搜索属性)。

因此,您可以(并且可能应该)简单地在您自己的 class 实例上调用 CopyFrom 函数,而不是转换或强制转换,将其传递给 FindMatchingControls 返回的 UITestControl。

我对 Linq 不够熟练,所以代码不够漂亮,但这样的东西会起作用:

List<HeaderTag> list = new List<HeaderTag>();
foreach (var item in new HeaderTag(window).FindMatchingControls())
{
    HeaderTag temp = new HeaderTag();
    temp.CopyFrom(item);
    list.Add(temp);
}

我不确定为什么不能转换,因为您的 class 是从 UITestControl 派生的。但是如果转换失败你应该使用 CopyFrom.