UI Automation - Modal dialog prevents automation
I am automating an application that, when the automation uses Select, opens a modal dialog. I've seen this issue discussed several places with a couple of suggestions. I've tried all of the suggestions without success. To post this issue I put together a small application that exhibits the same issue. The application contains a listbox and a button. When a listbox item selection changes it opens a message box. The button starts an automation sequence running which selects the first item and then tries to dismiss the dialog box by pressing the OK button.
The automation sequence is running in a non-UI MTA thread (Task). Because the Select blocks, it is invoked from another non-UI MTA thread (Task). When the main automation sequence moves on after starting the Select task, it hangs when it tries to Find the dialog that pops up.
I had seen suggestions to add a WindowOpenedEvent handler and push the OK button from there. I've included that in this application but the handler never gets called. In my real application the handler gets called for all other dialogs until one is opened from within the Select call.
Are there any other ideas about how to dismiss this dialog from the automation sequence?
C# .Net framework 4.8
MainWindow.xaml.cs:
using System;
using System.Diagnostics;
using System.Threading;
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());
Thread.Sleep (500); // Give the Select task time to do its thing
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>