UI 自动化控制桌面应用程序,然后单击菜单条



>我正在使用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() 方法。

要注意的是,菜单栏元素具有Children,而菜单项具有Descendants。如果使用 FindAll() 方法搜索子项,则找不到任何子项。

检查实用程序在编写 UI 自动化代码时非常有用 程序。它通常位于:

C:Program Files (x86)Windows Kits10binx64inspect.exe 

提供 32 位版本(binx86文件夹)。

如何进行:

  • 找到要与之交互的应用程序主窗口的句柄:
    • Process.GetProcessesByName() (或 ID), EnumWindows(), FindWindowEx() 可用于获取窗口句柄。
  • 获取MenuBar自动化元素。
    • 请注意,SystemMenu也包含在MenuBar中,可以使用元素名称来确定,它包含:"System"而不是"Application"
  • 名称枚举MenuBar或 FindFirst() 的子元素。
    • 请注意,菜单项名称和加速器已本地化。
  • 使用ExpandCollapsePattern.Expand()方法展开菜单以创建其子体元素。
  • NameAutomationIdAccessKey查找子菜单元素之一。
  • 使用InvokePattern.Invoke()方法调用子菜单操作。

当然,可以重复相同的操作来展开和调用嵌套子菜单的菜单项。

用于查找和展开Notepad.exe的文件菜单并调用ExitMenuItem 操作的示例代码和帮助程序方法:

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();
}
}

相关内容

最新更新