A drop-in replacement for OpenFileDialog in WPF/.NET Framework apps. Explorer-style dual-pane browser — tree on the left, file list on the right — with full MVVM architecture, real-time search, multi-selection, and Shell thumbnails for images.
- Breadcrumb bar — click any segment to jump up, or click the bar to type a path directly (Alt+D)
- Quick Access panel — Bureau, Documents, Images, Musique, Vidéos, Profil from known Windows folders
- Lazy-loaded TreeView — async enumeration, expand-on-first-open with sentinel pattern
- Keyboard shortcuts — F5 refresh, Backspace up, Alt+D address bar, Ctrl+F search, Enter confirm, Escape cancel
- Real-time search — Ctrl+F to focus the search box, 200 ms debounce, Escape to clear
- Multi-selection — Ctrl+click, Shift+click; file bar shows count when multiple files are selected
- 4-column ListView — Name (with Shell icon), Type, Size (KB), Date Modified
- Column sorting — click any header, click again to reverse
- UI virtualization —
VirtualizingStackPanelin Recycling mode; handles 10 000+ files without a freeze
- Shell icons —
SHGetFileInfowith extension-keyed cache; same icons as Windows Explorer - Thumbnails for images —
IShellItemImageFactoryvia P/Invoke for.jpg/.jpeg/.png/.gif/.bmp/.webp/.tiff; uses Windows thumbnail cache, async load, falls back to Shell icon - Reparse point filtering — symlinks and junctions excluded from the tree and list
- Network drives hidden by default — avoids accidental hangs on unreachable UNC paths
- Full MVVM —
OpenViewModel,FileSystemNodeViewModel,IFileSystemProvider - IFileSystemProvider abstraction — inject a test double for unit tests, or a VFS/cloud backend
- Async everywhere —
Task.Run+CancellationTokenfor all disk I/O; UI never blocks - Robust error handling —
UnauthorizedAccess,PathTooLong, USB hot-unplug, all handled gracefully
using CustomDialogBox;
var dialog = new Open { Owner = this };
if (dialog.ShowDialog() == true)
{
string path = dialog.SelectedPath; // full path of the selected file
}var dialog = new Open { Owner = this };
if (dialog.ShowDialog() == true)
{
IReadOnlyList<string> paths = dialog.SelectedPaths; // all selected files
string first = dialog.SelectedPath; // first (or only) selection
}Note: This project targets .NET Framework 4.7.2. Use MSBuild from Visual Studio 2022, not
dotnet build(the .NET SDK refuses to build old-style.csprojWPF projects).
# From a Developer Command Prompt for VS 2022
MSBuild CustomDialogBox\CustomDialogBox.csproj /t:Build /p:Configuration=ReleaseOutput lands in CustomDialogBox\bin\Release\CustomDialogBox.exe.
| OS | Windows 10 / 11 |
| .NET Framework | 4.7.2 or later |
| UI framework | WPF |
| Build tool | MSBuild (Visual Studio 2022) |
CustomDialogBox/
│
├── IFileSystemProvider.cs # Abstraction — inject test doubles or VFS backends
├── WindowsFileSystemProvider.cs # Default: wraps FileSystemService + DriveInfo
│
├── FileSystemNodeViewModel.cs # Tree node — lazy load, async icons/thumbnails, INotifyPropertyChanged
├── FileSystemService.cs # Static enumeration — EnumerateDirectories/Files, all exception handling
├── ShellIcons.cs # SHGetFileInfo (16×16 icons) + IShellItemImageFactory (thumbnails)
│
├── OpenViewModel.cs # Dialog state — drives, current list, search, selection, breadcrumbs
├── NavItem.cs # Immutable data item for breadcrumb segments and Quick Access entries
├── RelayCommand.cs # ICommand wrappers (generic + non-generic)
│
├── Open.xaml # Dialog layout — breadcrumb, Quick Access, TreeView, ListView
└── Open.xaml.cs # Thin code-behind — routes events to VM, handles keyboard and address bar
| Decision | Rationale |
|---|---|
| Sentinel child node | TreeView shows expand arrow before enumeration; replace on first expand |
async void LoadChildrenAsync() |
Fire-and-forget is intentional — UI should not await tree expansion |
CancellationToken per node |
Rapid expand/collapse does not accumulate background tasks |
Filter via CollectionViewSource |
Sort and filter share one ICollectionView; no data duplication |
IFileSystemProvider |
Makes OpenViewModel unit-testable without touching the real file system |
| Thumbnails lazy-loaded | 32×32 thumbnails via Windows thumbnail cache; falls back to Shell icon without a performance penalty |
public class MyCloudProvider : IFileSystemProvider
{
public FileSystemNodeViewModel[] GetChildren(string path, CancellationToken ct = default)
{
// query your API, return nodes
}
public DriveInfo[] GetDrives() => DriveInfo.GetDrives();
}
// Inject at construction
var dialog = new Open(new MyCloudProvider()) { Owner = this };The
Openwindow's constructor passes the provider through toOpenViewModel. You will need to expose apublic Open(IFileSystemProvider provider)overload — currently the constructor is parameterless but the underlying ViewModel already accepts the provider.
Override BtnOpen_Click in a subclass or subscribe to Closing to add your own guards (MIME check, size limit, signature verification, etc.). SelectedPaths gives you the full list before the dialog closes.
| Key | Action |
|---|---|
| Enter | Confirm selection (Ouvrir) |
| Escape | Cancel / close address bar edit |
| F5 | Refresh current directory |
| Backspace | Navigate to parent directory |
| Alt+D | Focus address bar (type a path directly) |
| Ctrl+F | Focus search box |
| Ctrl+click | Add to selection (multi-select) |
| Shift+click | Range selection |
| Double-click file | Confirm selection |
| Double-click folder | Navigate into folder |
-
.NET 6 / 8project target (SDK-style.csproj, WPF on modern .NET) -
IFileValidatorcomposable — max size, magic bytes, date range - File content preview pane (text, image, PDF first page)
- Pinned favorites in Quick Access (persist to
%APPDATA%) - NuGet package (pending API surface review)
Issues and PRs are welcome.
- Shell interop belongs in
ShellIcons.cs, not in ViewModels - Any disk I/O must be off the UI thread (
Task.Run+CancellationToken) - Code style: no
varfor non-obvious types, no regions, no XML doc on obvious members
MIT — see LICENSE. Ship it, fork it, teach with it.