【问题标题】:Using UI Automation, Winforms Button Invoking multiple times使用 UI 自动化,Winforms 按钮多次调用
【发布时间】:2012-09-17 11:36:58
【问题描述】:

我正在尝试在我的应用程序中使用MS UI Automation Framework 进行一些自动化测试。我现在的目标是监听 GUI 事件并记录它们,类似于 Windows SDK 中提供的示例 (TestScriptGeneratorSample)。

只需使用该演示应用程序,我就可以使用一个按钮启动一个简单的 Windows 窗体应用程序,并看到它将单击事件记录为“调用”UIA 事件。但是,对于按钮的每次点击,演示应用程序都会记录 4 个“调用”事件。这是为什么?使用 WPF 按钮时,我没有看到此问题。

我的猜测是,由于 System.Windows.Forms.Button 类支持 MSAA 而不是 UIA,因此桥接 MSAA 接口的 UIA 部分行为不端,或者至少以我无法理解且无法理解的方式运行'找不到任何有关的文档。 也许它正在报告鼠标按下、向上、单击和实际按钮按下的调用事件?

谁能解释这种行为,和/或提供一种解决方法,以便按下一个按钮会导致一个调用事件?

编辑:这是在 WinXP SP3 下。我刚刚安装了Windows Automation API 3.0 update 仍然看到相同的行为。

编辑 2: 我发现 this example 作者在其中不经意地提到此行为是 Win32 控件中的一个错误,但没有引用任何证据...

这是我的示例应用程序(上面有一个按钮的表单),以及其中包含的事件监听。添加对UIAutomationClientUIAutomationTypes 的引用。点击按钮,看到调用发生了四次而不是一次。

using System;
using System.Drawing;
using System.Windows.Automation;
using System.Windows.Forms;

namespace WindowsFormsApplication6
{
    public partial class Form1 : Form
    {
        private TextBox m_Output;

        public Form1()
        {
            InitializeComponent();

            // set up the GUI with a single button...
            Button b = new Button {Location = new Point(5, 5), Name = "Test", Text = "Click Me"};
            // ... and a textbox to write events to.
            m_Output = new TextBox { Location = new Point(5, 30), Name = "Output", Multiline = true, Size = new Size(250, 200) };

            this.Controls.Add(b);
            this.Controls.Add(m_Output);

            // get the button as an UIA element
            AutomationElement button = AutomationElement.FromHandle(b.Handle);
            // attach a handler to the button, listening for the Invoke event
            Automation.AddAutomationEventHandler(
                                                 InvokePattern.InvokedEvent,
                                                 button,
                                                 TreeScope.Element,
                                                 OnInvoked);
        }

        // Handler for button invoke events
        private void OnInvoked(object Sender, AutomationEventArgs E)
        {
            AppendText("Invoked: " + ((AutomationElement)Sender).Current.AutomationId);
        }

        // Just dumps text to the textbox
        private void AppendText(string Text)
        {
            if (m_Output.InvokeRequired)
            {
                m_Output.BeginInvoke((Action<string>)AppendText, Text);
            }
            else
            {
                m_Output.AppendText(DateTime.Now.ToString("hh:mm:ss.fff") + ": " + Text + Environment.NewLine);
            }
        }
    }
}

【问题讨论】:

  • +1 自动化框架很有趣。
  • 我查看了您的代码,这可能与您实现 AppendText 的方式有关。尝试使用Invoke 而不是BeginInvoke 看看是否有任何不同。另外,您使用的是哪个版本的 .NET?

标签: .net winforms ui-automation msaa


【解决方案1】:

对于它的价值,我通过将发出的多个事件过滤为一个来解决它。在测试过程中,我发现了以下内容:

  • .NET 按钮(即 Winforms)在单击时按顺序生成以下事件:
    1. 已调用
    2. 已调用
    3. 已调用
    4. 属性已更改(Name 属性)
    5. 已调用
  • Win32 按钮在某些情况下会生成以下事件(calc.exe 中的按钮):
    1. 属性已更改(HasKeyboardFocus 属性)
    2. 已调用
  • Win32 按钮在其他情况下会生成以下事件(保存文件对话框中的“取消”):
    1. 已调用
    2. 属性已更改(HasKeyboardFocus 属性)
    3. 已调用

使用与事件关联的AutomationElement 上的FrameworkId 属性,我可以区分第一种和第二种情况(对于.NET 按钮是"Winform",对于Win32 按钮是"Win32")。然后对于两个 Win32 场景,我只需确保在记录调用的事件之前获得 HasKeyboardFocus 属性更改事件。

我还没有看到这不起作用,因为我似乎总是得到HasKeyboardFocus 属性更改事件,即使按钮已经被聚焦(即我按下它两次)。

如果有人有的话,我仍然希望看到更多的见解......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 1970-01-01
    • 2018-07-04
    • 2011-07-12
    • 1970-01-01
    • 2021-11-21
    相关资源
    最近更新 更多