{"record":{"id":"21066340a82ce46f","repo":"lepoco/wpfui","slug":"you-cannot-unwatch-a-window-that-is-not-yet-loaded","errorCode":null,"errorMessage":"You cannot unwatch a window that is not yet loaded.","messagePattern":"You cannot unwatch a window that is not yet loaded\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Wpf.Ui/Appearance/SystemThemeWatcher.cs","lineNumber":130,"sourceCode":"            );\n            observedWindow.AddHook(WndProc);\n            _observedWindows.Add(observedWindow);\n        }\n    }\n\n    /// <summary>\n    /// Unwatches the window and removes the hook to receive messages from the system.\n    /// </summary>\n    public static void UnWatch(Window? window)\n    {\n        if (window is null)\n        {\n            return;\n        }\n\n        if (!window.IsLoaded)\n        {\n            throw new InvalidOperationException(\"You cannot unwatch a window that is not yet loaded.\");\n        }\n\n        IntPtr hWnd =\n            (hWnd = new WindowInteropHelper(window).Handle) == IntPtr.Zero\n                ? throw new InvalidOperationException(\"Could not get window handle.\")\n                : hWnd;\n\n        ObservedWindow? observedWindow = _observedWindows.FirstOrDefault(x => x.Handle == hWnd);\n\n        if (observedWindow is null)\n        {\n            return;\n        }\n\n        observedWindow.RemoveHook(WndProc);\n\n        _ = _observedWindows.Remove(observedWindow);\n    }","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/lepoco/wpfui/blob/ffebacd61058170cf63864b7d5aa730cffff848a/src/Wpf.Ui/Appearance/SystemThemeWatcher.cs#L112-L148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nSystemThemeWatcher.UnWatch(window); // window not loaded yet\n\n// after\nif (window.IsLoaded)\n{\n    SystemThemeWatcher.UnWatch(window);\n}","handlingStrategy":"validation","validationCode":"if (window is not null && window.IsLoaded) { SystemThemeWatcher.UnWatch(window); }","typeGuard":"static bool CanUnwatch(System.Windows.Window? w) => w is { IsLoaded: true };","tryCatchPattern":null,"preventionTips":["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."],"tags":["hwnd","lifecycle","window","unwatch"],"backgroundTag":null,"analyzedSha":"ffebacd61058170cf63864b7d5aa730cffff848a","analyzedAt":"2026-08-13T21:36:01.370Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}