访问上下文菜单

时间:2017-04-01 14:11:43

标签: vb.net microsoft-ui-automation

我正在尝试访问记事本的Context Menu UI AutomationElement,但是我很难这样做:

SELECT ST_MakePoint(-71.1043443253471, 42.3150676015829);

我的问题是,当我运行应用程序时,打开记事本上下文菜单但是UIAutomation似乎永远不会得到它的AutomationElement ......

这是Inspect.exe的截图:

Inspect Image

鉴于检查图片及其呈现的结构,我认为没有理由发生这种情况......有谁知道我可能会出错?

P.S。我是VB.NET的新手,但已经和VBA合作了2到3年,所以我为我可能有的任何坏习惯道歉......

1 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法。诀窍是订阅UIAutomation OpenMenuEvent。为此,我创建了一个ContextWatcher类:

Public Class ContextWatcher
    Public Shared Menu As AutomationElement
    Private Shared _EventHandler As AutomationEventHandler
    Public Shared Sub trackContext()
        _EventHandler = New AutomationEventHandler(AddressOf OnContextOpened)
        Automation.AddAutomationEventHandler(AutomationElement.MenuOpenedEvent, AutomationElement.RootElement, TreeScope.Descendants, _EventHandler)
    End Sub
    Public Shared Sub untrackContext()
        Automation.RemoveAutomationEventHandler(AutomationElement.MenuOpenedEvent, AutomationElement.RootElement, _EventHandler)
    End Sub
    Private Shared Sub OnContextOpened(src As Object, args As AutomationEventArgs)
        Console.WriteLine("Menu opened.")
        Dim element = TryCast(src, AutomationElement)
        If element Is Nothing Then
            Return
        Else
            Menu = element
        End If
    End Sub
End Class

要访问上下文菜单,我可以使用:

ContextWatcher.trackContext()

SendKeys.SendWait("+{F10}")

Dim context As AutomationElement
context = ContextWatcher.Menu
While context Is Nothing
    Console.WriteLine("Trying to get context again")
    Threading.Thread.Sleep(100)
    context = ContextWatcher.Menu
End While

' Do Stuff with context menu

ContextWatcher.untrackContext()
Imports System.Windows.Automation
Imports System.Windows.Forms
Module AutomateNotepad
    Sub Main()
        Dim wNotepad, document As AutomationElement

        'Get 'Untitled - Notepad' main window
        wNotepad = AutomationElement.RootElement.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "Untitled - Notepad"))

        'Get Notepad document element
        document = wNotepad.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "document"))

        'Set focus to document
        document.SetFocus()

        'Start watching for context menu
        ContextWatcher.trackContext()

        'Open context menu
        SendKeys.SendWait("+{F10}")

        'Get context menu from ContextWatcher class
        Dim context As AutomationElement
        context = ContextWatcher.Menu
        While context Is Nothing
            Console.WriteLine("Trying to get context again")
            Threading.Thread.Sleep(100)
            context = ContextWatcher.Menu
        End While

        'trigger undo
        invokeContextMenuItem(context, "Undo")

        'Stop watching for context menu
        ContextWatcher.untrackContext()
    End Sub

    Sub invokeContextMenuItem(context As AutomationElement, sMenuItem As String)
        'Get context menu children
        Dim controls As AutomationElementCollection = context.FindAll(TreeScope.Children, Condition.TrueCondition)

        'Loop over controls to find control with name sMenuItem
        Dim control As AutomationElement
        For Each control In controls
            If control.Current.Name = sMenuItem Then
                'Invoke control
                getInvokePattern(control).Invoke()
                Exit Sub
            End If
        Next
    End Sub

    'Helper function to get InvokePattern from UI Element
    Function getInvokePattern(element As AutomationElement) As InvokePattern
        Return element.GetCurrentPattern(InvokePattern.Pattern)
    End Function

    Public Class ContextWatcher
        Public Shared Menu As AutomationElement
        Private Shared _EventHandler As AutomationEventHandler
        Public Shared Sub trackContext()
            _EventHandler = New AutomationEventHandler(AddressOf OnContextOpened)
            Automation.AddAutomationEventHandler(AutomationElement.MenuOpenedEvent, AutomationElement.RootElement, TreeScope.Descendants, _EventHandler)
        End Sub
        Public Shared Sub untrackContext()
            Automation.RemoveAutomationEventHandler(AutomationElement.MenuOpenedEvent, AutomationElement.RootElement, _EventHandler)
        End Sub
        Private Shared Sub OnContextOpened(src As Object, args As AutomationEventArgs)
            Console.WriteLine("Menu opened.")
            Dim element = TryCast(src, AutomationElement)
            If element Is Nothing Then
                Return
            Else
                Menu = element
            End If
        End Sub
    End Class
End Module