C# UI自动化-模式对话框阻止自动化
我正在自动化一个应用程序,当自动化使用Select时,它会打开一个模式对话框,阻止自动化继续。我看到这个问题在几个地方讨论过,并提出了一些建议。我尝试了所有的建议,但都没有成功。为了发布这个问题,我将一个展示相同问题的小应用程序放在一起。该应用程序包含一个列表框和一个按钮。当列表框项目选择发生更改时,将打开一个消息框。该按钮启动自动序列运行,选择第一个项目,然后按“确定”按钮尝试关闭对话框 自动化序列正在非UI MTA线程任务中运行。由于Select会阻塞,因此会从另一个非UI MTA线程任务调用它。当主自动化序列在启动Select任务后继续运行时,当它试图查找弹出的对话框时将挂起 我看到了添加WindowOpenedEvent处理程序并从那里按下OK按钮的建议。我已经在这个应用程序中包含了它,但是处理程序从未被调用过。在我的实际应用程序中,所有其他对话框都会调用处理程序,直到从Select调用中打开一个对话框为止 关于如何从自动化序列中取消此对话框,还有其他想法吗 C.Net框架4.8 MainWindow.xaml.cs:C# UI自动化-模式对话框阻止自动化,c#,wpf,ui-automation,.net-framework-4.8,C#,Wpf,Ui Automation,.net Framework 4.8,我正在自动化一个应用程序,当自动化使用Select时,它会打开一个模式对话框,阻止自动化继续。我看到这个问题在几个地方讨论过,并提出了一些建议。我尝试了所有的建议,但都没有成功。为了发布这个问题,我将一个展示相同问题的小应用程序放在一起。该应用程序包含一个列表框和一个按钮。当列表框项目选择发生更改时,将打开一个消息框。该按钮启动自动序列运行,选择第一个项目,然后按“确定”按钮尝试关闭对话框 自动化序列正在非UI MTA线程任务中运行。由于Select会阻塞,因此会从另一个非UI MTA线程任务调
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Interop;
namespace AutomationSelectTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Task _task;
public MainWindow()
{
InitializeComponent();
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show("Selection changed");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var windowHandle = new WindowInteropHelper(this).Handle;
_task = Task.Factory.StartNew(() => AutomationSequence(windowHandle));
}
private static readonly System.Windows.Automation.Condition ButtonOkCondition = new AndCondition(
new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),
new PropertyCondition(AutomationElement.NameProperty, "OK"));
private static void AutomationSequence(IntPtr windowHandle)
{
var application = AutomationElement.FromHandle(windowHandle);
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, application, TreeScope.Subtree, Window_Opened);
var listBoxItem = application.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "ListBoxItem"));
var listBoxSelectionItemPattern = listBoxItem.GetCurrentPattern(SelectionItemPattern.Pattern) as SelectionItemPattern ?? throw new InvalidOperationException();
// Because the call to Select will block, run it as a separate task
var selectionTask = Task.Factory.StartNew(() => listBoxSelectionItemPattern.Select());
var dialog = application.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "Dialog"));
var buttonOk = dialog.FindFirst(TreeScope.Subtree, ButtonOkCondition);
var buttonOkInvokePattern = buttonOk.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern ?? throw new InvalidOperationException();
buttonOkInvokePattern.Invoke();
// Now wait for the Select to return
selectionTask.Wait();
Automation.RemoveAutomationEventHandler(WindowPattern.WindowOpenedEvent, application, Window_Opened);
}
private static void Window_Opened(object sender, AutomationEventArgs e)
{
// Never gets here
Debugger.Break();
}
}
}
MainWindow.xaml:
<Window x:Class="AutomationSelectTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AutomationSelectTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListBox HorizontalAlignment="Left" Height="144" Margin="10,10,0,0" VerticalAlignment="Top" Width="151" SelectionChanged="ListBox_SelectionChanged">
<ListBoxItem Content="ListBoxItem1"/>
<ListBoxItem Content="ListBoxItem2"/>
<ListBoxItem Content="ListBoxItem3"/>
</ListBox>
<Button Content="Run Automation" HorizontalAlignment="Left" Height="39" Margin="10,159,0,0" VerticalAlignment="Top" Width="151" Click="Button_Click"/>
</Grid>
</Window>
有人有什么想法吗?当前代码中存在竞争条件,因此必须在StartNew之后引入睡眠,以确保在调用FindFirst之前Select有时间运行。