0

vb.net を使用して Windows フォーム アプリケーションを自動化しようとしています。自動化したいプログラムのソースコードがありません。

Spy++ では、これまでのところボタンのハンドルを使用しており、問題なくボタンをクリックしています。しかし、ツールストリップ ボタンに関する問題に出くわし、それを回避するのに苦労しています。これらのボタンは(私が読んだことから)非表示または非表示であり、spy ++には表示されないため、ハンドルがないようです。したがって、ボタンが存在しないため、ボタンのハンドルを使用してクリックすることはできません。

この問題を解決するには、マウス カーソルを特定の画面位置に移動し、ウィンドウの位置を変更して、マウス クリック イベントを開始する必要がありました。ただし、自動化コードの実行中はマウスを使用できないため、この方法は最適ではありません。誰かが代替案を提案できますか? 私は解決策を求めてインターネットとこのサイトを 3 日間探し回っていますが、成功しませんでした。

どんな助けでも大歓迎です。

4

2 に答える 2

0

私は自分で問題を解決することができました!!! 嬉しいなぁ…笑。私はオートホットキーを試しませんでしたが、私が見つけた解決策は良いものです。少なくとも私はそうだと思います。ここに優れた説明があります... http://msdn.microsoft.com/en-us/magazine/cc163288.aspx

とにかく、解決策は、vb.net にプロジェクトに追加できる「UI オートメーション」ライブラリ/参照があることです。オンラインで何度か言及されているのを見ましたが、それをインポートする方法がわかりませんでした (申し訳ありませんが、vb.net/coding newby です)。とにかく、「UI Automation」参照をプロジェクトに追加してからインポートします。その後、ライブラリを使用して、画面上のすべてのコントロールを見つけることができます。これには、ツールストリップのすべてのボタンが含まれます。

どのように解決したかを示すために、以下にコードサンプルを追加しました。私はそれが何らかの形で厄介であり、おそらくもっとうまくできると確信していますが、うまくいきます. コード/ソリューションについてどう思うか教えてください。

コードを実行するには、ボタンのインデックスとツールストリップのインデックスを知る必要があります。デバッグ モードを通過する場合は、インデックスを手動でインクリメントし、正しいボタンが表示されるまで controlName を確認できます。以下の例では、親要素 (ウィンドウ)、子要素 (ツールストリップ)、子の子 (ツールストリップの下のすべてのボタン) を見つける必要がありました。

Imports system.windows.automation
Imports system.eventargs

'RoutedEvenArgs has to exist as a class so I declare it here...

Public class RoutedEventArgs Inherits EventArgs

end class

'my form code is all under one class - I'll probably break it up better
' but at the moment this is how it is

Public Class form1

Private Sub Button1_Click_1(ByVal sender As System.Object, _
                            ByVal e As System.EventArgs) Handles Button1.Click

'click the button of hte automation front end and 
' call the findtreeviewdescendants procedure

    FindTreeViewDescendants()

End Sub

Private Sub FindTreeViewDescendants()

'define the desktop as the rootelement as everywindow is a child of this element

Dim aedesktop As AutomationElement = AutomationElement.RootElement

'create an automationelementcollection variable to store the buttons

Dim aebuttons As AutomationElementCollection

'find the screen using the screen title 

aeform = aedesktop.FindFirst(TreeScope.Children, New PropertyCondition _
(AutomationElement.NameProperty, "Single Stock View"))

'find all the child controls (this brings back all controls including the toolstrip)

aebuttons = aeform.FindAll(TreeScope.Children, New PropertyCondition _(AutomationElement.IsControlElementProperty, True))

'create an automationelement to store the button and get information out of it

Dim a As AutomationElement

'each button, in the collection, has an index (incidentally the index number corresponds with the order in  which the window loads each of the elements into the window), in this case the toolstrip is index 1 as it's in the header of the screen

a = aebuttons.Item(1)

'get the child elements of the toolstrip element (something interesting is that in this case there were 19 elements but when you use findwindowex you only get back 4)

aebuttons = a.FindAll(TreeScope.Children, New PropertyCondition(AutomationElement.IsControlElementProperty, True))

'again use the index of the button to pull back the element information

a = aebuttons.Item(11)

'create a stringbuilder to store information about the element

Dim elementInfoCompile = New StringBuilder()

'identify the controlname, which in my case is the tooltip tag of the button (thus solving the problem of how I can find a button with an image instead of text in it)

Dim controlName As String
If (a.Current.Name = "") Then
controlName = "Unnamed control"
Else
controlName = a.Current.Name
End If

'identify the autoidname - which in all cases seemed to be null - I've no idea why but this didn't matter anyway

Dim autoIdName As String

If (a.Current.AutomationId = "") Then
autoIdName = "No AutomationID"
Else
autoIdName = a.Current.AutomationId
End If

'invoke a click of the button

InvokeControl(a)

End Sub 'FindTreeViewDescendants

'the rest is self-explanatory....

Private Sub InvokeControl(ByVal targetControl As AutomationElement)
Dim invokePattern As InvokePattern = Nothing

Try
invokePattern = _
DirectCast(targetControl.GetCurrentPattern(invokePattern.Pattern),  _
InvokePattern)
Catch e As ElementNotEnabledException
' Object is not enabled. 
Return
Catch e As InvalidOperationException
' Object doesn't support the InvokePattern control pattern 
Return
End Try

invokePattern.Invoke()

End Sub 'InvokeControl

End Class
于 2013-02-14T16:52:31.457 に答える
0

一般に、ツールストリップ ボタン (または実際にはインターフェイスで使用するすべてのボタン) とバックエンドのビジネス ロジックが分離されるように、コードを配置することをお勧めします。可能であれば、ボタン クリック ハンドラによって呼び出される関数を記述して、そこに「コード シーム」を作成します。

(VB で)

Private Sub btnSomeButton_Click(ByVal sender As System.Object, _
                                ByVal e As System.EventArgs) _
                                Handles btnSomeButton.Click
     BusinessLogicClass.DoSomeButtonWork()
End Sub

このようにして、他の関数で関数を簡単に呼び出し、自動化スクリプトでそれらを使用し、それらの単体テストとモックを記述し、多数ではなく 1 か所でリファクタリングできます。これを「デカップリング」と呼びます。特に「バッチモード」でプロセスを使用することを計画している場合、これは本当に優れたソリューションです。

于 2013-02-13T15:58:45.357 に答える