4

いくつかの自動テストのために、アプリケーションでMSUIオートメーションフレームワークを使用しようとしています。今のところ私の目標は、Windows SDKで提供されているサンプル(TestScriptGeneratorSample)と同様に、GUIイベントをリッスンして記録することです。

そのデモアプリケーションを使用するだけで、ボタン1つで単純なWindowsフォームアプリケーションを起動し、クリックイベントを「呼び出し」UIAイベントとして記録することを確認できます。ただし、ボタンをクリックするたびに、デモアプリケーションは4つの「呼び出し」イベントを記録します。何故ですか?WPFボタンを使用している場合、この問題は発生しません。

私の推測では、System.Windows.Forms.ButtonクラスはUIAではなくMSAAをサポートしているため、MSAAインターフェイスをブリッジしているUIAの部分が誤動作しているか、少なくとも私が理解できず、ドキュメントが見つからない方法で動作していると思います。たぶん、マウスを下、上、クリックしてから実際にボタンを押したときの呼び出しイベントを報告しているのでしょうか。

誰かがこの動作を説明したり、ボタンを1回押すと1回の呼び出しイベントが発生するように回避策を提供したりできますか?

編集:これはWinXPSP3の下にあります。Windows Automation API 3.0 アップデートをインストールしたところ、同じ動作が見られます。

編集2:著者がこの動作をWin32コントロールのバグとして不当に言及しているが、証拠を引用していないこの例を見つけました...

これが私のサンプルアプリケーション(ボタンが付いたフォーム)と、それに焼き付けられたイベントリスニングです。UIAutomationClientおよびへの参照を追加しますUIAutomationTypes。ボタンをクリックして、呼び出しが1回ではなく4回発生することを確認します。

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);
            }
        }
    }
}
4

1 に答える 1

0

価値のあることとして、発行された複数のイベントを 1 つにフィルター処理することで、この問題を回避しました。テスト中に、次のことがわかりました。

  • .NET ボタン (つまり、Winforms) は、クリックされると次のイベントを順番に生成します。
    1. 呼び出された
    2. 呼び出された
    3. 呼び出された
    4. プロパティが変更されました (Nameプロパティ)
    5. 呼び出された
  • Win32 ボタンは、一部のシナリオで次のイベントを生成します ( のボタンcalc.exe)。
    1. プロパティが変更されました (HasKeyboardFocusプロパティ)
    2. 呼び出された
  • Win32 ボタンは、他のシナリオで次のイベントを生成します (ファイル保存ダイアログの「キャンセル」)。
    1. 呼び出された
    2. プロパティが変更されました (HasKeyboardFocusプロパティ)
    3. 呼び出された

FrameworkIdイベントに関連付けられている のプロパティを使用して、最初と 2 番目の 2 つの状況 ( .NET ボタンとWin32 ボタンの場合)AutomationElementを区別できます。次に、2 つの Win32 シナリオでは、呼び出されたイベントを記録する前にプロパティ変更イベントを確実に取得します。"Winform""Win32"HasKeyboardFocus

HasKeyboardFocusボタンが既にフォーカスされていても (つまり、2 回押した場合)、 常にプロパティ変更イベントを取得しているように見えるため、これが機能しないことはまだ確認していません。

誰かがいくつか持っている場合、私はまだもう少し洞察を見たいと思います...

于 2012-10-29T20:55:50.277 に答える