From wpf-dev-pack
Discovers Prism IDialogAware modal dialogs in FlaUI UI automation for WPF testing. Handles titleless windows, empty titles, progress dialogs; verifies IsCancel ESC keys and status messages.
How this skill is triggered — by the user, by Claude, or both
Slash command
/wpf-dev-pack:flaui-prism-dialog-discoverysonnetThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Prism's `IDialogAware` dialogs in WPF-UI applications often use custom window styles (`TitlelessWindow`, `CommonWindow`) that make standard FlaUI modal discovery unreliable. This skill covers patterns for finding and verifying these dialogs.
Prism's IDialogAware dialogs in WPF-UI applications often use custom window styles (TitlelessWindow, CommonWindow) that make standard FlaUI modal discovery unreliable. This skill covers patterns for finding and verifying these dialogs.
Prism dialogs using TitlelessWindow style have no Title property. Standard modal search by title returns nothing.
Symptoms:
_mainWindow.ModalWindows returns windows but modal.Title is emptyFix — identify by child control type:
/// <summary>
/// Finds a Progress dialog by looking for a modal with a ProgressBar control.
/// TitlelessWindow style means Title is empty, so we identify by content.
/// </summary>
private AutomationElement? FindProgressDialog()
{
var modalWindows = _mainWindow.ModalWindows;
foreach (var modal in modalWindows)
{
var progressBar = modal.FindFirstDescendant(cf =>
cf.ByControlType(ControlType.ProgressBar));
if (progressBar is not null)
{
return modal;
}
}
return null;
}
For titled dialogs (CommonWindow with Title):
/// <summary>
/// Finds a modal dialog with a non-empty Title (e.g., warning, confirmation).
/// </summary>
private AutomationElement? FindTitledModal()
{
var modalWindows = _mainWindow.ModalWindows;
foreach (var modal in modalWindows)
{
if (!string.IsNullOrEmpty(modal.Title))
{
return modal;
}
}
return null;
}
General pattern — identify modal by unique child:
private AutomationElement? FindModalByChild(
Func<AutomationElement, bool> childMatcher)
{
foreach (var modal in _mainWindow.ModalWindows)
{
var descendants = modal.FindAllDescendants();
if (descendants.Any(childMatcher))
{
return modal;
}
}
return null;
}
// Usage: find modal containing a specific button text
var dialog = FindModalByChild(d =>
d.Name?.Contains("Cancel", StringComparison.OrdinalIgnoreCase) == true);
WPF buttons with IsCancel="True" close the dialog on ESC press. In Prism dialogs, this triggers IDialogAware.OnDialogClosed(). Testing this requires verifying both dialog closure and the application's response.
Pattern — ESC cancel with Status Bar verification:
// 1. Wait for dialog to appear
var dialog = RetryHelper.WaitForElement(
() => FindProgressDialog(),
TimeSpan.FromSeconds(10));
Assert.NotNull(dialog);
// 2. Press ESC (triggers IsCancel="True" button → CancelCommand)
Thread.Sleep(500); // Allow dialog to fully render
Keyboard.Press(VirtualKeyShort.ESCAPE);
// 3. Verify dialog closed
var closed = RetryHelper.WaitUntil(
() => FindProgressDialog() is null,
TimeSpan.FromSeconds(10));
Assert.True(closed, "ESC should close the dialog");
// 4. Verify cancellation via Status Bar message
// This distinguishes cancel from normal completion
var statusVerified = RetryHelper.WaitUntil(
() =>
{
var texts = _mainWindow.FindAllDescendants(cf =>
cf.ByControlType(ControlType.Text));
return texts.Any(t =>
t.Name?.Contains("canceled", StringComparison.OrdinalIgnoreCase) == true);
},
TimeSpan.FromSeconds(5));
Assert.True(statusVerified, "Status Bar should show 'canceled' message");
Why Status Bar verification matters:
VisionTaskCompleted(TaskEventReason.Canceled) event — unique to cancellationLoading test data via Ctrl+O requires interacting with the Windows file dialog, which is a separate process.
Pattern:
// Ctrl+O to open file dialog
DragHelper.ForceSetForeground(_mainWindow);
Thread.Sleep(300);
Keyboard.TypeSimultaneously(VirtualKeyShort.CONTROL, VirtualKeyShort.KEY_O);
Thread.Sleep(2000); // File dialog takes time to open
// Type file path and confirm
Keyboard.TypeSimultaneously(VirtualKeyShort.CONTROL, VirtualKeyShort.KEY_A);
Thread.Sleep(100);
Keyboard.Type(taskConfigPath);
Thread.Sleep(500);
Keyboard.Type(VirtualKeyShort.ENTER);
Thread.Sleep(3000); // Loading takes time
// Handle potential warning dialog (e.g., path validation)
var warningDialog = FindTitledModal();
if (warningDialog is not null)
{
Keyboard.Type(VirtualKeyShort.ENTER); // Dismiss warning
Thread.Sleep(500);
}
| Style | Title | How to Find |
|---|---|---|
CommonWindow (default) | Set via prism:Dialog.WindowStyle Setter | modal.Title |
TitlelessWindow | Empty | Child control type (ProgressBar, specific Button, etc.) |
CommonWindow with no Title Setter | Empty | Same as TitlelessWindow |
Thread.Sleep(2000) after Ctrl+O — Windows file dialog is cross-process, needs extra timeThread.Sleep(3000) after ENTER in file dialog — task config loading + FunctionBlock instantiationThread.Sleep(500) before ESC — allow dialog to fully render and receive keyboard focusRetryHelper.WaitUntil for state verification instead of fixed sleepnpx claudepluginhub christian289/dotnet-with-claudecode --plugin wpf-dev-packCreates WPF dialog windows including modal dialogs, MessageBox, custom settings dialogs, and common dialogs for confirmation prompts, settings windows, file/folder pickers.
Generates and runs batch UI test scripts for WinUI 3 apps. Covers element assertions, interactions, value checking, file pickers, flyouts, dialogs, persistence, and accessibility audits.
Sets up and runs E2E tests for Windows native desktop apps (WPF, WinForms, Win32/MFC, Qt) using pywinauto and Windows UI Automation. Covers testability setup, CI integration, and flaky test diagnosis.