【问题标题】:How to recognize WPF drawing visuals in UIAutomation?如何在 UIAutomation 中识别 WPF 绘图视觉效果?
【发布时间】:2014-10-02 22:14:45
【问题描述】:

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

// 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 技术,但 DrawingVisuals 不是从 UIElement 派生的,我不能添加 UIElements 到Canvas.VisualCollection
  2. 图像识别是一种选择,但我们 出于性能/维护方面的考虑,正在尝试避免这种情况。

【问题讨论】:

    标签: wpf ui-automation coded-ui-tests microsoft-ui-automation


    【解决方案1】:

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

    因此,如果您希望 UIAutomation 可以使用 UIElement(或类似 FrameworkElement 的派生元素),则需要将其添加到画布中。

    您可以创建自己的类,如下所述:Using DrawingVisual Objects 或使用自定义 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
        }
    }
    

    【讨论】:

    • 感谢西蒙的回复。在画布上使用 DrawingVisuals 而不是 UIElements 是有意识的决定,以帮助提高性能。我们的应用程序在画布上添加了大量形状。我想知道是否还有其他方法。
    • 再次感谢西蒙。这应该有效。我有类似的东西,我在 OnCreateAutomationPeer 中传递视觉效果,我试图跟上视觉集合的变化,但有点卡在那里。您通过在 owner 下添加的 Children 属性解决了这个问题。
    • @SimonMourier :我很好奇...您之前的帖子指出只能从 UI 自动化中看到 UIElementCanvas(和孩子喜欢:Path)继承自 UIElement,那么为什么它们对 Microsoft 的 UIA 不可见?
    • @Pressacco - “可以”并不意味着“将”。如果一个类派生自 UIElement,则它“可以”从 UIA 中可见,但只有当它(或其层次结构)覆盖 OnCreateAutomationPeer 并返回非空值时,它“才会”。 Canvas 没有,Panel 没有,FrameworkElement 没有。通常,大多数控件和文档都可以。画布不是控件。但你可以派生和覆盖自己
    • @SimonMourier:感谢您的澄清:“可以与意志”。非常感谢。
    猜你喜欢
    • 2012-03-20
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    相关资源
    最近更新 更多