lepoco/wpfui · error · InvalidOperationException
You cannot unwatch a window that is not yet loaded.
Error message
You cannot unwatch a window that is not yet loaded.
What it means
Thrown by SystemThemeWatcher.UnWatch when the passed window is not yet loaded. Unwatching requires the HWND to locate and detach the installed hook; an unloaded window has no handle and no hook, so the operation is invalid and explicitly rejected.
Source
Thrown at src/Wpf.Ui/Appearance/SystemThemeWatcher.cs:130
);
observedWindow.AddHook(WndProc);
_observedWindows.Add(observedWindow);
}
}
/// <summary>
/// Unwatches the window and removes the hook to receive messages from the system.
/// </summary>
public static void UnWatch(Window? window)
{
if (window is null)
{
return;
}
if (!window.IsLoaded)
{
throw new InvalidOperationException("You cannot unwatch a window that is not yet loaded.");
}
IntPtr hWnd =
(hWnd = new WindowInteropHelper(window).Handle) == IntPtr.Zero
? throw new InvalidOperationException("Could not get window handle.")
: hWnd;
ObservedWindow? observedWindow = _observedWindows.FirstOrDefault(x => x.Handle == hWnd);
if (observedWindow is null)
{
return;
}
observedWindow.RemoveHook(WndProc);
_ = _observedWindows.Remove(observedWindow);
}View on GitHub (pinned to ffebacd610)
Solutions
- Only call UnWatch after confirming window.IsLoaded is true.
- Pair Watch/UnWatch symmetrically around the Loaded/Unloaded or Shown/Closed events so the window state is consistent.
- Guard the call: if (!window.IsLoaded) return; before invoking UnWatch when shutdown ordering is uncertain.
Example fix
// before
SystemThemeWatcher.UnWatch(window); // window not loaded yet
// after
if (window.IsLoaded)
{
SystemThemeWatcher.UnWatch(window);
} Defensive patterns
Strategy: validation
Validate before calling
if (window is not null && window.IsLoaded) { SystemThemeWatcher.UnWatch(window); } Type guard
static bool CanUnwatch(System.Windows.Window? w) => w is { IsLoaded: true }; Prevention
- Only call UnWatch on loaded windows.
- Pair Watch/UnWatch symmetrically around consistent lifecycle events.
- Guard shutdown paths with an IsLoaded check to avoid ordering issues.
When it happens
Trigger: Calling SystemThemeWatcher.UnWatch(window) where window.IsLoaded is false. Common when unwatching is wired into a lifecycle event that fires before Loaded (constructor, Initialized) or after the window was never shown.
Common situations: Unsubscribing in a Closing/Unloaded handler that runs on a window that was watched but never fully loaded, or calling UnWatch defensively during shutdown on a window that was constructed but not shown.
Related errors
- Could not get window handle.
- Unable to determine the window source.
- Window handle cannot be empty
- Failed to get the current `_desiredWidth`.
- Use {nameof(Close)} with MessageBoxResult instead
AI-assisted analysis of lepoco/wpfui@ffebacd610 (2026-08-13).
Data as JSON: /api/errors/21066340a82ce46f.
Report an issue: GitHub.