簡體   English   中英

UI自動化控制桌面應用程序並單擊菜單條

[英]UI Automation Control Desktop Application and Click on Menu Strip

我正在使用 UI 自動化單擊菜單條控件。
我已經預先填充了文本框,現在也可以調用按鈕了。

但是我想遍歷到菜單欄選擇一個選項讓我們說應該打開它的子​​菜單項的文件,然后單擊子菜單按鈕,比如說退出。

我怎樣才能實現它,下面是我的代碼,直到現在,

AutomationElement rootElement = AutomationElement.RootElement;

if (rootElement != null)
{
    System.Windows.Automation.Condition condition = new PropertyCondition
        (AutomationElement.NameProperty, "This Is My Title");
    rootElement.FindAll(TreeScope.Children, condition1);
    AutomationElement appElement = rootElement.FindFirst(TreeScope.Children, condition);
    
    if (appElement != null)
    {
        foreach (var el in eles)
        {
            AutomationElement txtElementA = GetTextElement(appElement, el.textboxid);
            if (txtElementA != null)
            {
                ValuePattern valuePatternA =
                    txtElementA.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
                valuePatternA.SetValue(el.value);
                el.found = true;
            }
        }

        System.Threading.Thread.Sleep(5000);
        System.Windows.Automation.Condition condition1 = new PropertyCondition
            (AutomationElement.AutomationIdProperty, "button1");
        AutomationElement btnElement = appElement.FindFirst
            (TreeScope.Descendants, condition1);

        InvokePattern btnPattern =
            btnElement.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
        btnPattern.Invoke();

菜單項支持ExpandCollapsePattern 您可以在展開子MenuItem后調用它。 這將創建MenuItem后代對象。 如果您不展開 Menu,則它沒有后代,因此沒有任何可調用的內容。
使用InvokePattern執行調用

要獲取ExpandCollapsePatternInvokePattern ,請使用TryGetCurrentPattern方法:

[MenuItem].TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out object pattern)

[MenuItem].TryGetCurrentPattern(InvokePattern.Pattern, out object pattern)

如果該方法返回成功的結果,則可以調用Expand()Invoke()方法。

要注意MenuBar元素有Children ,而MenuItemDescendants 如果您使用FindAll()方法搜索子項,您將找不到任何子項。

Inspect 實用程序在編寫 UI 自動化過程時非常有用。 它通常位於:

 C:\\Program Files (x86)\\Windows Kits\\10\\bin\\x64\\inspect.exe

32 位版本可用( \\bin\\x86\\文件夾)。

如何進行:

  • 找到要與之交互的應用程序主窗口的句柄:
  • 獲取MenuBar自動化MenuBar
    • 請注意, SystemMenu也包含在MenuBar ,可以使用元素名稱確定它,它包含: "System"而不是"Application"
  • 按名稱枚舉MenuBarFindFirst()的子元素。
    • 請注意,菜單項名稱和加速鍵是本地化的。
  • 使用ExpandCollapsePattern.Expand()方法展開 Menu,以創建其 Descendants 元素。
  • NameAutomationIdAccessKey查找子菜單元素AccessKey
  • 使用InvokePattern.Invoke()方法調用子菜單操作。

當然,可以重復相同的操作來擴展和調用嵌套子菜單的 MenuItem。

用於查找和展開Notepad.exe的文件菜單並調用Exit MenuItem 操作的示例代碼和幫助程序方法:

public void CloseNotepad()
{
    IntPtr hWnd = IntPtr.Zero;
    using (Process p = Process.GetProcessesByName("notepad").FirstOrDefault()) {
        hWnd = p.MainWindowHandle;
    }
    if (hWnd == IntPtr.Zero) return;
    var window = GetMainWindowElement(hWnd);
    var menuBar = GetWindowMenuBarElement(window);
    var fileMenu = GetMenuBarMenuByName(menuBar, "File");

    if (fileMenu is null) return;

    // var fileSubMenus = GetMenuSubMenuList(fileMenu);
    bool result = InvokeSubMenuItemByName(fileMenu, "Exit", true);
}

private AutomationElement GetMainWindowElement(IntPtr hWnd) 
    => AutomationElement.FromHandle(hWnd) as AutomationElement;

private AutomationElement GetWindowMenuBarElement(AutomationElement window)
{
    var condMenuBar = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuBar);
    var menuBar = window.FindAll(TreeScope.Descendants, condMenuBar)
        .OfType<AutomationElement>().FirstOrDefault(ui => !ui.Current.Name.Contains("System"));
    return menuBar;
}

private AutomationElement GetMenuBarMenuByName(AutomationElement menuBar, string menuName)
{
    var condition = new AndCondition(
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuItem),
        new PropertyCondition(AutomationElement.NameProperty, menuName)
    );
    if (menuBar.Current.ControlType != ControlType.MenuBar) return null;
    var menuItem = menuBar.FindFirst(TreeScope.Children, condition);
    return menuItem;
}

private List<AutomationElement> GetMenuSubMenuList(AutomationElement menu)
{
    if (menu.Current.ControlType != ControlType.MenuItem) return null;
    ExpandMenu(menu);
    var submenus = new List<AutomationElement>();
    submenus.AddRange(menu.FindAll(TreeScope.Descendants,
        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.MenuItem))
                                               .OfType<AutomationElement>().ToArray());
    return submenus;
}

private bool InvokeSubMenuItemByName(AutomationElement menuItem, string menuName, bool exactMatch)
{
    var subMenus = GetMenuSubMenuList(menuItem);
    AutomationElement namedMenu = null;
    if (exactMatch) {
        namedMenu = subMenus.FirstOrDefault(elm => elm.Current.Name.Equals(menuName));
    }
    else {
        namedMenu = subMenus.FirstOrDefault(elm => elm.Current.Name.Contains(menuName));
    }
    if (namedMenu is null) return false;
    InvokeMenu(namedMenu);
    return true;
}

private void ExpandMenu(AutomationElement menu)
{
    if (menu.TryGetCurrentPattern(ExpandCollapsePattern.Pattern, out object pattern))
    {
        (pattern as ExpandCollapsePattern).Expand();
    }
}

private void InvokeMenu(AutomationElement menu)
{
    if (menu.TryGetCurrentPattern(InvokePattern.Pattern, out object pattern))
    {
        (pattern as InvokePattern).Invoke();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM