Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7b81223
Add UI elements for copying current element state and display notific…
dualbios Nov 2, 2025
616330b
Add clipboard functionality and notification for copying element state
dualbios Nov 2, 2025
e83204d
Merge pull request #38 from FlaUI/copy-patterns-to-clipboard
dualbios Nov 9, 2025
6fceb46
Enhance MainViewModel and ElementViewModel to support application nam…
dualbios Nov 10, 2025
072d626
Add recording functionality to MainViewModel and UI controls for star…
dualbios Nov 10, 2025
4e95050
Add window handle selection functionality and update MainViewModel to…
dualbios Nov 18, 2025
5896290
Add window picking functionality with cursor change and button event …
dualbios Nov 18, 2025
7119cc0
Add ElementOverlay and NativeCursors classes for window highlighting …
dualbios Nov 18, 2025
ff237f8
element overlay
dualbios Dec 12, 2025
889c1fd
Add IsStringNullOrEmptyToVisibleConverter and bind ApplicationName to UI
dualbios Dec 12, 2025
4ee6f40
Refactor MainViewModel: remove unused fields and methods, streamline …
dualbios Dec 12, 2025
c2580cc
Refactor code for consistency; adjust formatting and remove unnecessa…
dualbios Jan 3, 2026
0455c89
Add CopyDetailsToClipboard button and notification to ProcessWindow
dualbios Jan 12, 2026
f1beba0
Add ListView styles and resource dictionary; update Generic.xaml to i…
dualbios Jan 12, 2026
27e716a
Enhance AboutView; refactor resource management and add FlaUiIcon
dualbios Jan 14, 2026
a876a1f
reorginize resourse
dualbios Jan 14, 2026
a9e5883
Update project files for version 3.0.0; remove Styles folder and enha…
dualbios Jan 20, 2026
9c5c6b1
Update image in README for Dark theme section
dualbios Jan 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ obj/

# Artifacts
artifacts/
src/.idea/
*.user
desktop.ini
72 changes: 63 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,89 @@
# FlaUInspect

![FlaUInspect](/FlaUInspect.png?raw=true)

### New 2.0.0
New has been [released](https://github.com/FlaUI/FlaUInspect/releases/tag/v2.0.0)!
## NEW 3.0.0

New version released! Download it [here](https://github.com/FlaUI/FlaUInspect/releases/tag/v3.0.0)

This is a major update with a lot of changes:
- using separated window for process
- new UI
- Dark and Light theme support
- implement settings
- new icons
- new application selection bounding
- redesigned:
- property grid
- control tree
- menu buttons
- mouse hover control selection
- improved performance
- fixed and redesigned 3-state highlight of selected control

#### Screenshot of new UI:

Main window and selection application highlights.

<img width="600" alt="Image" src="https://github.com/user-attachments/assets/f0a23f20-f994-4a17-b83b-3da6c96e337f" />

Main window display application and allow user to select it from list or press and hold Find window button and drag mouse over applications. The FlaUinspect will highlight the application under mouse cursor and select id in the list.

Hover mode

<img width="600" alt="Image" src="https://github.com/user-attachments/assets/53fbcd61-cd93-4f09-9962-13be900f4c95" />

Select Hover mode button and hold Ctrl key and move mouse over application windows. The FlaUInspect will highlight the control under mouse cursor and select it in the tree.

Highlight selection

<img width="600" alt="Image" src="https://github.com/user-attachments/assets/7e5c8767-e75f-449b-adb5-cbd55522f405" />

Select Selection Mode button and click on any control in the application. The FlaUInspect will highlight the selected control in the application.

Highlight selectin and Dark theme

<img width="600" alt="Image" src="https://github.com/user-attachments/assets/7b9db566-6e3b-459d-bc49-1715a172a189" />

FlaUinspect supports Light and Dark theme currently.

### 2.0.0

Download it [here](https://github.com/FlaUI/FlaUInspect/releases/tag/v2.0.0)

This is a major update with a lot of changes:

* Complete rewrite of the application
* New UI
* New features
* Much more stable
* Based on .NET 8
* Three separate versions for UIA2 and UIA3 and default with choosing on startup


### Installation
To install FlaUInspect, either build it yourself or get the zip from the releases page here on GitHub (https://github.com/FlaUI/FlaUInspect/releases).

To install FlaUInspect, either build it yourself or get the zip from the releases page here on
GitHub (https://github.com/FlaUI/FlaUInspect/releases).

### Description
There are various tools around which help inspecting application that should be ui tested or automated. Some of them are:

There are various tools around which help inspecting application that should be ui tested or automated. Some of them
are:

* VisualUIAVerify
* Inspect
* UISpy
* and probably others
Most of them are old and sometimes not very stable and (if open source), a code mess to maintain.
Most of them are old and sometimes not very stable and (if open source), a code mess to maintain.

FlaUInspect is supposed to be a modern alternative, based on [FlaUI](https://github.com/Roemer/FlaUI).

On startup of FlaUInspect, you can choose if you want to use UIA2 or UIA3 (see [FAQ](https://github.com/Roemer/FlaUI/wiki/FAQ) why you can't use both at the same time).
On startup of FlaUInspect, you can choose if you want to use UIA2 or UIA3 (
see [FAQ](https://github.com/Roemer/FlaUI/wiki/FAQ) why you can't use both at the same time).
You can use pre-built versions of FlaUInspect.UIA2 and FlaUInspect.UIA3 if you want to use a version of UIA.


###### Main Screen

![Main Screen](https://github.com/user-attachments/assets/6212341b-9776-4907-9edc-acc00073c92e)

##### Tool buttons
Expand All @@ -43,10 +96,11 @@ You can use pre-built versions of FlaUInspect.UIA2 and FlaUInspect.UIA3 if you w
| Show XPath | Enable this option to show a simple XPath to the current selected element in the StatusBar of FlaUInspect |

### Release Notes 2.0.0

* Deployed FlaUInspect, FlaUInspect.UIA2, and FlaUInspect.UIA3 applications with hardcoded UI2 or UI3 selection.
* Refactored code and implemented asynchronous operations.
* Redesigned the property grid; collapsed groups remain collapsed after selecting another control.
* Added a third selection state: highlighting the selected control in an application.
* Included a refresh button for each item in the tree.
*Refined icons.
*Refined icons.

11 changes: 8 additions & 3 deletions src/FlaUInspect/App.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<Application x:Class="FlaUInspect.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="ApplicationStart">
<Application.Resources />
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/LightTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
137 changes: 121 additions & 16 deletions src/FlaUInspect/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,153 @@
using System.Reflection;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows;
using FlaUI.Core;
using FlaUInspect.Core;
using FlaUInspect.Core.Logger;
using FlaUInspect.Settings;
using FlaUInspect.ViewModels;
using FlaUInspect.Views;
using Microsoft.Extensions.DependencyInjection;

namespace FlaUInspect;

public partial class App {
private void ApplicationStart(object sender, StartupEventArgs e) {

public static IServiceProvider Services { get; private set; } = null!;
public static FlaUiAppOptions FlaUiAppOptions { get; } = new ();

public static InternalLogger Logger { get; } = new ();

protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);

ServiceCollection services = new ();
services.AddSingleton<ISettingsService<FlaUiAppSettings>>(_ => new JsonSettingsService<FlaUiAppSettings>(Path.Combine(AppContext.BaseDirectory, $"appsettings.json")));
Services = services.BuildServiceProvider();

ISettingsService<FlaUiAppSettings> settingsService = Services.GetRequiredService<ISettingsService<FlaUiAppSettings>>();
FlaUiAppSettings flaUiAppSettings = settingsService.Load();
ApplyAppOption(flaUiAppSettings);

//InternalLogger logger = new ();
Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
StartupViewModel startupViewModel = new ();
StartupWindow startupWindow = new (Logger) { DataContext = startupViewModel };
Current.MainWindow = startupWindow;
startupWindow.Show();

//Preload light theme
SetTheme(flaUiAppSettings);

Task.Run(() => startupViewModel.Init());

return;
AssemblyFileVersionAttribute? versionAttribute = Assembly.GetEntryAssembly()?.GetCustomAttribute(typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute;

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Unreachable code detected

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Unreachable code detected

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Unreachable code detected

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Unreachable code detected

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Unreachable code detected

Check warning on line 45 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Unreachable code detected
string applicationVersion = versionAttribute?.Version ?? "N/A";
InternalLogger logger = new ();
string windowHandle = string.Empty;

if (e.Args.Length > 0) {
windowHandle = e.Args[0];
}

#if AUTOMATION_UIA3
MainViewModel mainViewModel = new (AutomationType.UIA3, applicationVersion, logger);
MainViewModel mainViewModel = new (AutomationType.UIA3, applicationVersion, windowHandle, logger);
MainWindow mainWindow = new () { DataContext = mainViewModel };

//Re-enable normal shutdown mode.
Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
Current.MainWindow = mainWindow;
mainWindow.Show();
#elif AUTOMATION_UIA2
MainViewModel mainViewModel = new (AutomationType.UIA2, applicationVersion, logger);
MainViewModel mainViewModel = new (AutomationType.UIA2, applicationVersion, windowHandle, logger);
MainWindow mainWindow = new() { DataContext = mainViewModel };

//Re-enable normal shutdown mode.
Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
Current.MainWindow = mainWindow;
mainWindow.Show();
#else
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
ChooseVersionWindow dialog = new ();
// Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
// ChooseVersionWindow dialog = new ();
//
// if (dialog.ShowDialog() == true) {
//
// MainViewModel mainViewModel = new (dialog.SelectedAutomationType, applicationVersion, windowHandle, Logger);
// MainWindow mainWindow = new () { DataContext = mainViewModel };
//
// //Re-enable normal shutdown mode.
// Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
// Current.MainWindow = mainWindow;
// mainWindow.Show();
// }
#endif
}

if (dialog.ShowDialog() == true) {
public static void ApplyAppOption(FlaUiAppSettings settings) {
// Apply theme
Current.Dispatcher.Invoke(() => {
SetTheme(settings);
});

MainViewModel mainViewModel = new (dialog.SelectedAutomationType, applicationVersion, logger);
MainWindow mainWindow = new () { DataContext = mainViewModel };
ThicknessConverter converter = new ();
FlaUiAppSettings cloneSetting = settings.Clone() as FlaUiAppSettings;

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Converting null literal or possible null value to non-nullable type.

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Converting null literal or possible null value to non-nullable type.

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Converting null literal or possible null value to non-nullable type.

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Converting null literal or possible null value to non-nullable type.

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Converting null literal or possible null value to non-nullable type.

Check warning on line 93 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Converting null literal or possible null value to non-nullable type.

//Re-enable normal shutdown mode.
Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
Current.MainWindow = mainWindow;
mainWindow.Show();
if (settings.HoverOverlay != null) {
Thickness hoverMargin = (Thickness)converter.ConvertFromString(cloneSetting.HoverOverlay.Margin);

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Unboxing a possibly null value.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA2)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Unboxing a possibly null value.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Unboxing a possibly null value.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Dereference of a possibly null reference.

Check warning on line 96 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Dereference of a possibly null reference.
FlaUiAppOptions.HoverOverlay = () => new ElementOverlay(
new ElementOverlayConfiguration(cloneSetting.HoverOverlay.Size,
hoverMargin,
ColorTranslator.FromHtml(cloneSetting.HoverOverlay.OverlayColor),
ElementOverlay.GetRectangleFactory(cloneSetting.HoverOverlay.OverlayMode)));
} else {
FlaUiAppOptions.HoverOverlay = FlaUiAppOptions.DefaultOverlay;
}
#endif

if (settings.SelectionOverlay != null) {
Thickness selectionMargin = (Thickness)converter.ConvertFromString(cloneSetting.SelectionOverlay.Margin);

Check warning on line 107 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (UIA3)

Dereference of a possibly null reference.

Check warning on line 107 in src/FlaUInspect/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Dereference of a possibly null reference.
FlaUiAppOptions.SelectionOverlay = () => new ElementOverlay(
new ElementOverlayConfiguration(cloneSetting.SelectionOverlay.Size,
selectionMargin,
ColorTranslator.FromHtml(cloneSetting.SelectionOverlay.OverlayColor),
ElementOverlay.GetRectangleFactory(cloneSetting.SelectionOverlay.OverlayMode)));
} else {
FlaUiAppOptions.SelectionOverlay = FlaUiAppOptions.DefaultOverlay;
}

if (settings.PickOverlay != null) {
Thickness pickMargin = (Thickness)converter.ConvertFromString(cloneSetting.PickOverlay.Margin);
FlaUiAppOptions.PickOverlay = () => new ElementOverlay(
new ElementOverlayConfiguration(cloneSetting.PickOverlay.Size,
pickMargin,
ColorTranslator.FromHtml(cloneSetting.PickOverlay.OverlayColor),
ElementOverlay.GetRectangleFactory(cloneSetting.PickOverlay.OverlayMode)));
} else {
FlaUiAppOptions.PickOverlay = FlaUiAppOptions.DefaultOverlay;
}
}

private static void SetTheme(FlaUiAppSettings settings) {
ResourceDictionary newTheme = new();

switch (settings.Theme) {
case "Dark":
newTheme.Source = new Uri("/FlaUInspect;component/Themes/DarkTheme.xaml", UriKind.Relative);
break;
default:
newTheme.Source = new Uri("/FlaUInspect;component/Themes/LightTheme.xaml", UriKind.Relative);
break;
}

// Remove existing theme dictionaries
for (int i = Current.Resources.MergedDictionaries.Count - 1; i >= 0; i--) {
ResourceDictionary dict = Current.Resources.MergedDictionaries[i];

if (dict.Source != null && (dict.Source.OriginalString.Contains("Themes/DarkTheme.xaml") || dict.Source.OriginalString.Contains("Themes/LightTheme.xaml"))) {
Current.Resources.MergedDictionaries.RemoveAt(i);
}
}

// Add the new theme dictionary
Current.Resources.MergedDictionaries.Add(newTheme);
}
}
38 changes: 38 additions & 0 deletions src/FlaUInspect/Controls/Buttons.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button" >
<Setter Property="BorderThickness" Value="{DynamicResource PrimaryThickness}"/>
<Setter Property="Background" Value="{DynamicResource PrimaryBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryBorderBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
<Setter Property="Width" Value="96"/>
<Setter Property="Padding" Value="10"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource PrimaryCornerRadius}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource PrimaryHoverBrush}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{DynamicResource PrimaryPressedBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{DynamicResource PrimaryDisabledBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryDisabledBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource DisabledTextBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Loading