Vb.net 访问上下文菜单

Vb.net 访问上下文菜单,vb.net,microsoft-ui-automation,Vb.net,Microsoft Ui Automation,我正在尝试访问记事本的上下文菜单UI AutomationElement,但是我很难做到: Imports System.Windows.Automation Imports System.Windows.Forms Module AutomateNotepad Sub Main() Dim wNotepad, document As AutomationElement wNotepad = AutomationElement.RootElement.Fi

我正在尝试访问记事本的上下文菜单UI AutomationElement,但是我很难做到:

Imports System.Windows.Automation
Imports System.Windows.Forms
Module AutomateNotepad
    Sub Main()
        Dim wNotepad, document As AutomationElement
        wNotepad = AutomationElement.RootElement.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "Untitled - Notepad"))

        document = wNotepad.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "document"))
        document.SetFocus()

        SendKeys.SendWait("+{F10}")

        context = AutomationElement.RootElement.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "context"))
        While context Is Nothing
            Console.WriteLine("Trying to get context again")
            Threading.Thread.Sleep(100)
            context = AutomationElement.RootElement.FindFirst(TreeScope.Children, New PropertyCondition(AutomationElement.NameProperty, "context"))
        End While

        MsgBox("Found it!")

    End Sub
End Module
我的问题是,当我运行应用程序时,记事本上下文菜单会打开,但UIAutomation似乎从未获得它的AutomationElement

这是Inspect.exe的屏幕截图:

鉴于检查图片和它呈现的结构,我看不出为什么会发生这种情况。。。有人知道我哪里会出错吗


另外,我对VB.NET非常陌生,但已经在VBA工作了2-3年,所以我为我可能有的任何坏习惯道歉…

我已经找到了解决问题的方法。诀窍是订阅UIEvent。为此,我创建了一个
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

如果使用.net,请去掉
GoTo
语句…有什么原因吗?是的,确实有。它不仅与控制流有关,而且会使代码难以读取和维护。他们决不是邪恶的,这是我所看到的对GoTo的滥用<代码>如果,
案例
等将证明您的条件是合理的。。。目前,您的代码流是这样的,它将继续循环
,直到上下文成为某种东西,但它永远不会是
而不是什么都不是
,因为代码是错误的,您可能最终会收到
StackOverflowException
。有趣的。。。就我个人而言,我发现:''令人恶心。。。