InvokePattern
InvokePattern是UIA中最常用的Pattern之一,WPF和Winform中的button控件都支持InvokePattern。
对InvokePattern的Invoke()方法的调用应立即返回,没有出现阻止情况。但是,此行为完全依赖于 Microsoft UI 自动化提供程序实现。在调用 Invoke()会引起阻止问题(如Winform中的模式对话框,但是WPF中的对话框的处理方式和winform不同,所以可以使用Invoke()方法来操作WPF中的模式对话框,因为WPF中的模式对话框不会出现阻止的问题)的情况下,要调用此方法,则需要另起线程来操作。
using System;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
namespace UIATest
{
class Program
{
static void Main( string[] args)
{
Process process = Process.Start( @" F:\CSharpDotNet\AutomationTest\ATP\WpfApp\bin\Debug\WpfApp.exe ");
int processId = process.Id;
AutomationElement element = FindElementById(processId, " button1 ");
InvokePattern currentPattern = GetInvokePattern(element);
currentPattern.Invoke();
}
/// <summary>
/// Get the automation elemention of current form.
/// </summary>
/// <param name="processId"> Process Id </param>
/// <returns> Target element </returns>
public static AutomationElement FindWindowByProcessId( int processId)
{
AutomationElement targetWindow = null;
int count = 0;
try
{
Process p = Process.GetProcessById(processId);
targetWindow = AutomationElement.FromHandle(p.MainWindowHandle);
return targetWindow;
}
catch (Exception ex)
{
count++;
StringBuilder sb = new StringBuilder();
string message = sb.AppendLine( string.Format( " Target window is not existing.try #{0} ", count)).ToString();
if (count > 5)
{
throw new InvalidProgramException(message, ex);
}
else
{
return FindWindowByProcessId(processId);
}
}
}
/// <summary>
/// Get the automation element by automation Id.
/// </summary>
/// <param name="windowName"> Window name </param>
/// <param name="automationId"> Control automation Id </param>
/// <returns> Automatin element searched by automation Id </returns>
public static AutomationElement FindElementById( int processId, string automationId)
{
AutomationElement aeForm = FindWindowByProcessId(processId);
AutomationElement tarFindElement = aeForm.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, automationId));
return tarFindElement;
}
#region InvokePattern helper
/// <summary>
/// Get InvokePattern
/// </summary>
/// <param name="element"> AutomationElement instance </param>
/// <returns> InvokePattern instance </returns>
public static InvokePattern GetInvokePattern(AutomationElement element)
{
object currentPattern;
if (!element.TryGetCurrentPattern(InvokePattern.Pattern, out currentPattern))
{
throw new Exception( string.Format( " Element with AutomationId '{0}' and Name '{1}' does not support the InvokePattern. ",
element.Current.AutomationId, element.Current.Name));
}
return currentPattern as InvokePattern;
}
#endregion
}
}
被测程序xaml代码如下:
<Window x:Class="WpfApp.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="219" Width="353">
<Grid>
<Button Height="23" HorizontalAlignment="Left" Click="button1_Click" Margin="50,0,0,62" Name="button1" VerticalAlignment="Bottom" Width="75">Button</Button>
</Grid>
</Window>
对应的cs文件:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Use InvokePattern invoke button.");
}
}
}
本文主要针对InvokePattern的Invoke方法来操作button控件。
关于您提到的
在调用 Invoke() 会引起阻止问题
原因是UIAutomation对于WPF的实现是native的, 通信是通过named pipe
对于WinForm等Win32的实现是DCOM Message, 也就是Windows Message, 所以需要message pump
不过无论如何, 把test client中的main thread标记为STAThread, 都因该没有问题
希望作者能多介绍下UI Automation中更多的知识, 比如UI Event怎么用,还有常见的问题, 比如timming issue等
在调用 Invoke() 会引起阻止问题
此问题困扰我很久,谢谢解答,对于UI Automation中的UI Event我接触的比较少,实在抱歉,但我会尽自己最大的努力,还望多多帮忙啊