提问者:小点点

如何在UIAutomation中识别WPF绘图视觉对象?


我们的应用程序有一个画布,我们在其中添加绘图视觉效果(如线条、多边形等)

// sample code

var canvas = new Canvas(); // create canvas
var visuals = new VisualCollection(canvas); // link the canvas to the visual collection
visuals.Add(new DrawingVisual()); // add the visuals to the canvas
visuals.Add(new DrawingVisual());

我们的目标是通过自动化将这些视觉对象添加到画布中,并验证它们是否正确添加。我们使用基于Microsoft UIAutomation的框架。

当使用像“检查”这样的工具来检查视觉结构时,我找不到画布。做了一些研究,发现你需要覆盖UIElement中的OnCreateAutomationPeer方法,并返回适用的AutomationPeer对象才能在自动化中看到它。

进行了更改,现在我可以看到画布,但是我仍然看不到画布下添加的任何视觉效果。

有人能帮我理解问题是什么吗?

尝试过的事情/替代方案:

  1. 尝试使用OnCreateAutomationPeer技术,但DrawingVisual不是从UIElement派生的,我无法将UIElement添加到Canvas. VisualCollection
  2. 图像识别是一种选择,但出于性能/维护考虑,我们正试图避免它。

共1个答案

匿名用户

从UIAutomation中只能看到UIElement(如您所见,OnCreateAutomationPeer从此类开始,而不是从Visual类开始)。

因此,如果您希望UIAutomation可以使用它,则需要将UIElement(或像FrameworkElement一样派生)添加到画布中。

您可以像这里描述的那样创建自己的类:使用DrawingVisual Object或使用自定义UserControl或使用适合您需要的现有类,但它必须以某种方式派生自UIElement。

一旦你有了一个好的类,你可以使用默认的AutomationPeer或覆盖该方法并更密切地适应。

如果你想保留Visual对象,一种解决方案是修改包含对象(但它仍然需要从UIElement派生)。例如,这里如果我按照链接中的文章,我可以编写一个自定义的包含对象(而不是你的示例代码的画布,所以你可能必须稍微适应),如下所示:

public class MyVisualHost  : UIElement
{
    public MyVisualHost()
    {
        Children = new VisualCollection(this);
    }

    public VisualCollection Children { get; private set; }


    public void AddChild(Visual visual)
    {
        Children.Add(visual);
    }

    protected override int VisualChildrenCount
    {
        get { return Children.Count; }
    }

    protected override Visual GetVisualChild(int index)
    {
        return Children[index];
    }

    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new MyVisualHostPeer(this);
    }

    // create a custom AutomationPeer for the container
    private class MyVisualHostPeer : UIElementAutomationPeer
    {
        public MyVisualHostPeer(MyVisualHost owner)
            : base(owner)
        {
        }

        public new MyVisualHost Owner
        {
            get
            {
                return (MyVisualHost)base.Owner;
            }
        }

        // a listening client (like UISpy is requesting a list of children)
        protected override List<AutomationPeer> GetChildrenCore()
        {
            List<AutomationPeer> list = new List<AutomationPeer>();
            foreach (Visual visual in Owner.Children)
            {
                list.Add(new MyVisualPeer(visual));
            }
            return list;
        }
    }

    // create a custom AutomationPeer for the visuals
    private class MyVisualPeer : AutomationPeer
    {
        public MyVisualPeer(Visual visual)
        {
        }

        // here you'll need to implement the abstrat class the way you want
    }
}