ToolStrip按钮的自动化单击“问题”

时间:2013-02-13 15:43:48

标签: automation spy++ toolstripbutton

我正在尝试使用vb.net自动化Windows窗体应用程序。我没有自动化程序的源代码。

使用Spy ++,到目前为止,我一直在使用按钮的句柄,并且一直没有问题地点击按钮。但是,我遇到了工具条按钮的问题,我一直在努力解决它。这些按钮是隐藏的或不可见的(从我读过的内容)并且它们没有出现在spy ++中,所以它们似乎没有句柄;因此我不能使用按钮的句柄来单击它,因为它不存在。

要解决此问题,我必须将鼠标光标移动到特定的屏幕位置,重新定位窗口并启动鼠标单击事件。尽管在自动化代码运行时无法使用鼠标,但这种方法并不是最好的方法。有人可以建议替代方案吗?我一直在网上搜索互联网和这个网站三天没有成功的解决方案。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:0)

通常,最好安排代码,使得工具条按钮(或者 在界面上使用的任何按钮)和后端的业务逻辑之间存在分离。如果可能的话,通过编写一个将由按钮点击处理程序调用的函数在那里创建一个“代码缝”,即使它像

一样简单

(在VB中)

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

通过这种方式,您可以轻松地在其他函数中调用该函数,在自动化脚本中使用它们,为它们编写单元测试和模拟,并在一个地方重构而不是很多。这称为“解耦”。这是一个真正优越的解决方案,特别是如果您计划以“批处理模式”使用该过程。

答案 1 :(得分:0)

我自己设法解决了这个问题!我很开心......哈哈。我没有尝试使用autohotkeys,但我找到的解决方案是一个很好的解决方案,或者至少我认为它是。这里提供了一个很好的解释...... 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