2017-04-01 1 views
1

J'essaie d'accéder au menu contextuel interface utilisateur AutomationElement du Bloc-notes, mais je me bats pour le faire:accès Menu contextuel

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 

Mon problème est que quand je lance l'application, le menu contextuel du bloc-notes ouvre mais UIAutomation ne semble jamais obtenir le AutomationElement de celui-ci ...

C'est une capture d'écran de Inspect.exe:

Inspect Image

Compte tenu de l'image d'inspection et de la structure qu'elle présente, je ne vois pas pourquoi cela se produirait ... Est-ce que quelqu'un sait où je pourrais me tromper?

P.S. Je suis très nouveau sur VB.NET mais j'ai travaillé avec VBA pendant 2-3 ans donc je m'excuse pour toutes les mauvaises habitudes que j'ai pu avoir ...

+0

Si vous utilisez .net s'il vous plaît se débarrasser des déclarations 'GoTo' ... Tous – Codexer

+0

raison pour cela ...? – Sancarn

+0

Oui, en effet. C'est à propos de flux de contrôle et il peut rendre le code difficile à lire et à maintenir. Ils ne sont en aucun cas mauvais, c'est le mauvais usage de 'GoTo' que j'ai vu ...' If', 'Case' etc. justifierait vos conditions ... Actuellement, la façon dont votre code circule maintenant, il continuera à boucler' jusqu'à ce que context' *** soit *** quelque chose, mais ce ne sera jamais 'Not Nothing' car le code est faux, vous pouvez éventuellement recevoir une' StackOverflowException' éventuellement. – Codexer

Répondre

1

J'ai trouvé une solution à mon problème. L'astuce consiste à s'abonner à UIAutomation OpenMenuEvent. Pour ce faire, je créé une classe ContextWatcher: Menu

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 

Pour accéder au contexte, je peux l'utiliser:

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