Skip to content

Improve Theme.cs#4302

Draft
Jack251970 wants to merge 21 commits intodevfrom
copilot/fix-cast-exception-bug
Draft

Improve Theme.cs#4302
Jack251970 wants to merge 21 commits intodevfrom
copilot/fix-cast-exception-bug

Conversation

@Jack251970
Copy link
Member

@Jack251970 Jack251970 commented Feb 27, 2026

This pull request makes several improvements and bug fixes to the theme and window styling logic in Theme.cs. The main focus is on making theme resource management more robust, improving drop shadow effect handling, ensuring safe brush usage, and enhancing dispatcher/thread safety for UI updates.

Theme resource management and robustness:

  • Refactored how theme resources are updated by wrapping resource addition in a try/catch block to handle InvalidCastException, preventing crashes when resource dictionaries contain unexpected types. (UpdateResourceDictionary, Flow.Launcher.Core/Resource/Theme.csL103-R124)
  • Improved dispatcher usage in async UI update methods (RefreshFrameAsync, SetBlurForWindowAsync) to ensure thread safety and avoid exceptions when called from non-UI threads. (RefreshFrameAsync, [1]; SetBlurForWindowAsync, [2]

Drop shadow and style application:

  • Reworked the logic for adding and removing drop shadow effects to create new unsealed styles, copy relevant setters, and correctly adjust margins, ensuring that effects are applied and removed cleanly without modifying the original style in place. (AddDropShadowEffectToCurrentTheme, RemoveDropShadowEffectFromCurrentTheme, Flow.Launcher.Core/Resource/Theme.csL480-R632)
  • Improved the handling of drop shadow and blur effects so that they interact correctly depending on the theme and system capabilities, and ensured corner preferences and effects are set and removed in the correct order. (AutoDropShadow, [1] [2]

Brush and resource safety:

Resource dictionary and style retrieval improvements:

Minor refactors and cleanups:

  • Cleaned up and clarified variable names and comments throughout the file for better readability. (Multiple locations)

Most important changes:

Theme resource management and thread safety:

  • Wrapped resource dictionary updates in a try/catch to handle InvalidCastException, preventing crashes when adding new theme resources.
  • Ensured all UI updates via dispatcher are thread-safe and only run on the UI thread, adding checks and proper invocation for RefreshFrameAsync and SetBlurForWindowAsync. [1] [2]

Drop shadow and style handling:

  • Refactored drop shadow effect logic to create new, unsealed styles and correctly adjust margins and effects, ensuring clean application and removal of visual effects.
  • Improved the interaction between blur and drop shadow effects, ensuring correct order and conditions for applying/removing effects and setting window corner preferences. [1] [2]

Brush and resource safety:

  • Added a helper to safely create caret brush values, avoiding shared mutable brushes and ensuring brushes are frozen when possible.

Resource dictionary and style retrieval:

  • Improved robustness when retrieving styles and resource dictionary entries, checking for existence before casting to prevent null reference exceptions. [1] [2]

Copilot AI and others added 2 commits February 27, 2026 14:39
…validation on Windows theme change

Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 27, 2026 14:48
@prlabeler prlabeler bot added the bug Something isn't working label Feb 27, 2026
@github-actions github-actions bot added this to the 2.2.0 milestone Feb 27, 2026
@gitstream-cm
Copy link

gitstream-cm bot commented Feb 27, 2026

Be a legend 🏆 by adding a before and after screenshot of the changes you made, especially if they are around UI/UX.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Wraps resource dictionary updates in defensive checks, adds a private helper to derive CaretBrush values from Foreground safely, freezes newly created brushes for immutability, makes CopyStyle static, hardens dispatcher usage in theme refresh/blur async flows, and limits frame refresh on theme change to the System color scheme. (≈33 words)

Changes

Cohort / File(s) Summary
Theme resource and brush handling
Flow.Launcher.Core/Resource/Theme.cs
Add GetNewCaretValue(object) to map Foreground → CaretBrush (handles DynamicResourceExtension, SolidColorBrush, other types). Wrap resource-dictionary additions in try/catch for InvalidCastException. Replace direct CaretBrush additions with guarded helper usage. Create new SolidColorBrush instances and call Freeze() before assigning. Make CopyStyle(Style, Style) static and adapt usages. Refactor async dispatcher checks in RefreshFrameAsync / SetBlurForWindowAsync.
Main window theme refresh
Flow.Launcher/MainWindow.xaml.cs
ActualApplicationThemeChanged now calls RefreshFrameAsync only when the color scheme is System (conditional refresh).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as MainWindow
  participant Theme as Theme
  participant Disp as Dispatcher
  participant Win as Window

  UI->>Theme: ActualApplicationThemeChanged(event)
  alt ColorScheme == System
    Theme->>Disp: RefreshFrameAsync()
    Disp-->>Theme: Ensure on UI thread (reinvoke if needed)
    Theme->>Theme: Resolve Foreground (including DynamicResource)
    Theme->>Theme: GetNewCaretValue(foreground)
    Theme->>Theme: Create new SolidColorBrush & Freeze()
    Theme->>Win: Apply brush/setters (CopyStyle called statically)
    Theme->>Disp: SetBlurForWindowAsync() (dispatcher guard)
  else
    UI-->>Theme: Skip RefreshFrameAsync
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • onesounds
  • taooceros
  • jjw24
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Improve Theme.cs' is vague and generic, using non-descriptive language that does not convey meaningful information about the changeset. Use a more specific title that reflects the main fix, such as 'Fix InvalidCastException in Theme resource updates' or 'Add defensive handling for brush and resource assignments in Theme.cs'.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements defensive handling for InvalidCastException [#4298], adds try-catch around resource dictionary updates, introduces GetNewCaretValue for safer resource mapping, and freezes brushes for immutability, addressing core exception prevention requirements.
Out of Scope Changes check ✅ Passed All changes focus on Theme.cs brush/resource handling and MainWindow.xaml.cs theme refresh logic directly related to fixing the casting exception and resource handling [#4298].
Description check ✅ Passed The PR description is comprehensive, directly related to the changeset, and clearly documents improvements to theme and window styling logic with specific focus areas.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch copilot/fix-cast-exception-bug

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request suppresses a spurious error dialog that appears when users change Windows themes or accent colors. The error is caused by a WPF framework bug where SystemResources.InvalidateTreeResources incorrectly attempts to clone Color structs as if they were Freezable or Expression objects, resulting in an InvalidCastException that the application cannot prevent.

Changes:

  • Added IsRecoverableSystemResourceException method to detect the specific WPF system resource invalidation exception
  • Integrated the new exception check into ErrorReporting.Report to suppress the error dialog while still logging the exception
  • Added comprehensive documentation explaining the WPF framework issue

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
Flow.Launcher/Helper/ExceptionHelper.cs Added new method to detect InvalidCastException from WPF's SystemResources.InvalidateTreeResources
Flow.Launcher/Helper/ErrorReporting.cs Integrated the new exception check to prevent error dialog from being shown

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ource invalidation on Windows theme change"

This reverts commit 372f142.
Refactored caret and background brush assignment to avoid sharing mutable instances and ensure proper resource referencing. Added GetNewCaretValue helper for safe caret brush creation. Brushes for backgrounds are now frozen for performance. Improved foreground value retrieval and dynamic resource key extraction. Made some methods static for clarity and consistency. Enhances resource management and reliability in theme handling.
@prlabeler prlabeler bot added Code Refactor enhancement New feature or request labels Feb 28, 2026
@coderabbitai coderabbitai bot removed bug Something isn't working enhancement New feature or request labels Feb 28, 2026
@Jack251970 Jack251970 changed the title Suppress spurious error dialog on Windows theme/accent color change Fix cast object of type 'System.Windows.Media.Color' to type 'System.Windows.Expression' exception Feb 28, 2026
@Jack251970 Jack251970 requested a review from Copilot February 28, 2026 07:17
@prlabeler prlabeler bot added the bug Something isn't working label Feb 28, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Flow.Launcher.Core/Resource/Theme.cs (1)

814-819: ⚠️ Potential issue | 🟡 Minor

Remove ToString() when looking up DynamicResource keys in ResourceDictionary.

At line 814, converting dynamicResource.ResourceKey to string via ToString() violates WPF resource lookup semantics. ResourceDictionary requires matching the actual key object (e.g., ComponentResourceKey), not its string representation. This inconsistency is evident at line 260, where the code correctly preserves ResourceKey object identity.

Proposed fix
- var resourceKey = dynamicResource.ResourceKey.ToString();
+ var resourceKey = dynamicResource.ResourceKey;

- if (Resources.Contains(resourceKey))
+ if (resourceKey != null && Resources.Contains(resourceKey))
{
    var colorResource = Resources[resourceKey];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Core/Resource/Theme.cs` around lines 814 - 819, The code is
converting dynamicResource.ResourceKey to a string before lookup which breaks
WPF resource key identity; in the Theme.cs block around the dynamicResource
handling, stop calling ToString() and use the ResourceKey object directly when
checking and retrieving from the ResourceDictionary (i.e., replace the use of
var resourceKey = dynamicResource.ResourceKey.ToString() and subsequent
Resources.Contains(resourceKey)/Resources[resourceKey] calls with checks that
use dynamicResource.ResourceKey itself so ComponentResourceKey and other
non-string keys resolve correctly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@Flow.Launcher.Core/Resource/Theme.cs`:
- Around line 814-819: The code is converting dynamicResource.ResourceKey to a
string before lookup which breaks WPF resource key identity; in the Theme.cs
block around the dynamicResource handling, stop calling ToString() and use the
ResourceKey object directly when checking and retrieving from the
ResourceDictionary (i.e., replace the use of var resourceKey =
dynamicResource.ResourceKey.ToString() and subsequent
Resources.Contains(resourceKey)/Resources[resourceKey] calls with checks that
use dynamicResource.ResourceKey itself so ComponentResourceKey and other
non-string keys resolve correctly).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 372f142 and 60b92c5.

📒 Files selected for processing (1)
  • Flow.Launcher.Core/Resource/Theme.cs

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Jack251970 Jack251970 enabled auto-merge February 28, 2026 07:29
Previously, the theme was refreshed on every theme change event.
Now, `_theme.RefreshFrameAsync()` is only called if the color
scheme setting is set to "System", preventing unnecessary
refreshes in other scenarios.
@gitstream-cm
Copy link

gitstream-cm bot commented Feb 28, 2026

🥷 Code experts: jjw24

jjw24, Jack251970 have most 👩‍💻 activity in the files.
Jack251970, jjw24 have most 🧠 knowledge in the files.

See details

Flow.Launcher.Core/Resource/Theme.cs

Activity based on git-commit:

jjw24 Jack251970
FEB
JAN
DEC
NOV
OCT 12 additions & 2 deletions
SEP 2 additions & 2 deletions

Knowledge based on git-blame:
jjw24: 99%
Jack251970: 1%

Flow.Launcher/MainWindow.xaml.cs

Activity based on git-commit:

jjw24 Jack251970
FEB
JAN
DEC
NOV 1 additions & 1 deletions
OCT 8 additions & 7 deletions
SEP 1547 additions & 49 deletions

Knowledge based on git-blame:
Jack251970: 100%

✨ Comment /gs review for LinearB AI review. Learn how to automate it here.

@coderabbitai coderabbitai bot removed the bug Something isn't working label Feb 28, 2026
Refactored RefreshFrameAsync and SetBlurForWindowAsync to check Dispatcher access before invoking UI updates, ensuring thread safety and reducing unnecessary Dispatcher calls. Also removed redundant code and unused using directive.
@coderabbitai coderabbitai bot added the bug Something isn't working label Feb 28, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Flow.Launcher.Core/Resource/Theme.cs (1)

829-833: ⚠️ Potential issue | 🟡 Minor

Remove ToString() and add null check for ResourceKey before ResourceDictionary lookup.

ResourceDictionary accepts object keys, not just strings. Calling ToString() on dynamicResource.ResourceKey can fail to find keys if they're non-string types, and doesn't guard against null values.

🔧 Proposed fix
-    var resourceKey = dynamicResource.ResourceKey.ToString();
+    var resourceKey = dynamicResource.ResourceKey;

     // find key in resource and return color.
-    if (Resources.Contains(resourceKey))
+    if (resourceKey != null && Resources.Contains(resourceKey))
     {
         var colorResource = Resources[resourceKey];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Core/Resource/Theme.cs` around lines 829 - 833, The code in
Theme.cs currently calls dynamicResource.ResourceKey.ToString() and then uses
Resources.Contains(resourceKey); change this to first check for null on
dynamicResource.ResourceKey and, if non-null, use the ResourceKey object itself
(not ToString()) when checking and retrieving from the ResourceDictionary. In
other words, replace the ToString() usage with a null-checked object reference
to dynamicResource.ResourceKey and pass that object into Resources.Contains and
subsequent lookup so non-string keys are handled correctly (refer to
dynamicResource.ResourceKey and the Resources.Contains(...) / ResourceDictionary
lookup in Theme.cs).
♻️ Duplicate comments (2)
Flow.Launcher.Core/Resource/Theme.cs (2)

679-683: ⚠️ Potential issue | 🔴 Critical

Dispatch the correct callback in SetBlurForWindowAsync.

Line 681 invokes RefreshFrameAsync instead of SetBlurForWindowAsync, so this method’s blur path is not what runs when called off the UI thread.

🔧 Proposed fix
 public async Task SetBlurForWindowAsync()
 {
-    if (Application.Current?.Dispatcher.CheckAccess() != true)
+    var dispatcher = Application.Current?.Dispatcher;
+    if (dispatcher == null)
+    {
+        return;
+    }
+
+    if (!dispatcher.CheckAccess())
     {
-        await Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync);
+        await dispatcher.InvokeAsync(SetBlurForWindowAsync).Task.Unwrap();
         return;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Core/Resource/Theme.cs` around lines 679 - 683, The dispatcher
call in SetBlurForWindowAsync is invoking RefreshFrameAsync instead of
re-dispatching SetBlurForWindowAsync, so the blur logic isn't executed when
called off the UI thread; update the code inside SetBlurForWindowAsync to call
await Application.Current?.Dispatcher.InvokeAsync(() =>
SetBlurForWindowAsync(window, enable, animate)) (or the appropriate delegate
that calls SetBlurForWindowAsync with the original parameters) so the same
method runs on the UI thread rather than RefreshFrameAsync, preserving
await/async semantics and returning afterward.

647-651: ⚠️ Potential issue | 🟠 Major

Fix dispatcher null-safety and nested task awaiting in RefreshFrameAsync.

Line 649 still uses Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync); if Application.Current is null this becomes an await on null. Also this dispatches Func<Task> and should explicitly await the underlying operation task chain.

🔧 Proposed fix
 public async Task RefreshFrameAsync()
 {
-    if (Application.Current?.Dispatcher.CheckAccess() != true)
+    var dispatcher = Application.Current?.Dispatcher;
+    if (dispatcher == null)
+    {
+        return;
+    }
+
+    if (!dispatcher.CheckAccess())
     {
-        await Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync);
+        await dispatcher.InvokeAsync(RefreshFrameAsync).Task.Unwrap();
         return;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Core/Resource/Theme.cs` around lines 647 - 651,
RefreshFrameAsync currently does await
Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync) which can await
null if Application.Current is null and also dispatches a Func<Task> without
awaiting the inner task; fix by caching local var dispatcher =
Application.Current?.Dispatcher, null-checking it (return if null), use
dispatcher.CheckAccess() on that local, and when dispatching call
dispatcher.InvokeAsync(() => RefreshFrameAsync()) and await the returned
operation's Task (or Unwrap the Task<Task>) so the inner RefreshFrameAsync is
awaited properly; reference RefreshFrameAsync, Application.Current,
Dispatcher.InvokeAsync and Dispatcher.CheckAccess in the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Flow.Launcher.Core/Resource/Theme.cs`:
- Around line 261-290: GetNewCaretValue currently can return non-Brush values
(e.g., a Color) which may be assigned to TextBoxBase.CaretBrushProperty; update
GetNewCaretValue to explicitly handle when foregroundPropertyValue is a Color by
constructing a SolidColorBrush from that Color (set Opacity/Freeze as done for
SolidColorBrush branch) and return that brush; keep existing handling for
DynamicResourceExtension and SolidColorBrush, and ensure the method never
returns a raw Color so CaretBrush always receives a Brush.
- Around line 109-122: The add/remove logic currently sets _oldResource to the
new dictionary before confirming the add and swallows InvalidCastException,
causing _oldResource to become null and later NREs; fix by not assigning
_oldResource until after the new dictionary is successfully added (move the
_oldResource = dictionaryToUpdate assignment inside the try block after
Application.Current.Resources.MergedDictionaries.Add(...)), catch the
InvalidCastException and log the full exception (include ex.ToString()) rather
than swallowing it, and do not set _oldResource = null in the catch—either leave
the prior dictionary in place or restore it if you removed it earlier; also add
a defensive null-check where _oldResource.Source.AbsolutePath is accessed to
avoid NREs.

---

Outside diff comments:
In `@Flow.Launcher.Core/Resource/Theme.cs`:
- Around line 829-833: The code in Theme.cs currently calls
dynamicResource.ResourceKey.ToString() and then uses
Resources.Contains(resourceKey); change this to first check for null on
dynamicResource.ResourceKey and, if non-null, use the ResourceKey object itself
(not ToString()) when checking and retrieving from the ResourceDictionary. In
other words, replace the ToString() usage with a null-checked object reference
to dynamicResource.ResourceKey and pass that object into Resources.Contains and
subsequent lookup so non-string keys are handled correctly (refer to
dynamicResource.ResourceKey and the Resources.Contains(...) / ResourceDictionary
lookup in Theme.cs).

---

Duplicate comments:
In `@Flow.Launcher.Core/Resource/Theme.cs`:
- Around line 679-683: The dispatcher call in SetBlurForWindowAsync is invoking
RefreshFrameAsync instead of re-dispatching SetBlurForWindowAsync, so the blur
logic isn't executed when called off the UI thread; update the code inside
SetBlurForWindowAsync to call await
Application.Current?.Dispatcher.InvokeAsync(() => SetBlurForWindowAsync(window,
enable, animate)) (or the appropriate delegate that calls SetBlurForWindowAsync
with the original parameters) so the same method runs on the UI thread rather
than RefreshFrameAsync, preserving await/async semantics and returning
afterward.
- Around line 647-651: RefreshFrameAsync currently does await
Application.Current?.Dispatcher.InvokeAsync(RefreshFrameAsync) which can await
null if Application.Current is null and also dispatches a Func<Task> without
awaiting the inner task; fix by caching local var dispatcher =
Application.Current?.Dispatcher, null-checking it (return if null), use
dispatcher.CheckAccess() on that local, and when dispatching call
dispatcher.InvokeAsync(() => RefreshFrameAsync()) and await the returned
operation's Task (or Unwrap the Task<Task>) so the inner RefreshFrameAsync is
awaited properly; reference RefreshFrameAsync, Application.Current,
Dispatcher.InvokeAsync and Dispatcher.CheckAccess in the change.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 966bcdd and a83da2b.

📒 Files selected for processing (1)
  • Flow.Launcher.Core/Resource/Theme.cs

Added early returns if Application.Current is null in RefreshFrameAsync and SetBlurForWindowAsync to prevent null reference exceptions. Updated dispatcher access checks and ensured the correct method is invoked asynchronously for each case, improving robustness and reliability.
@Jack251970 Jack251970 force-pushed the copilot/fix-cast-exception-bug branch from e90aa02 to 84ed1fa Compare February 28, 2026 15:40
@Jack251970 Jack251970 added bug Something isn't working and removed Code Refactor labels Mar 1, 2026
@Jack251970 Jack251970 marked this pull request as draft March 1, 2026 04:16
auto-merge was automatically disabled March 1, 2026 04:16

Pull request was converted to draft

Jack251970 and others added 12 commits March 1, 2026 12:19
Improve IsBlurTheme to check blur support directly in the
current theme's resource dictionary, ensuring precise and
context-specific detection. Updated related logic and comments
for clarity.
Renamed the variable themeName to theme in the UpdateFonts method
to improve naming consistency. No functional changes were made.
Reworked how drop shadow effects are added and removed by creating new unsealed Style instances instead of modifying sealed ones. Resources, triggers, and setters are copied, with margin adjustments and effect setter management to ensure reliability. Introduced GetNewWindowBorderStyle helper for style copying.
Explicitly set DispatcherPriority.Render when invoking RefreshFrameAsync and SetBlurForWindowAsync on the application's dispatcher. This ensures theme-related UI changes are processed with rendering priority, improving responsiveness and visual consistency. Also added System.Windows.Threading import for access to DispatcherPriority.
Refactored theme resource dictionary lookups to safely check for "WindowBorderStyle" before accessing, preventing potential exceptions. Updated three methods to handle missing styles gracefully and standardized resource key checks. GetWindowBorderStyleBackground now returns transparent if style is missing.
Renamed IsBlurTheme to IsThemeBlurEnabled and moved system
backdrop support checks out of the helper function. Blur
availability is now determined by combining theme settings
and system capability in the calling code. Updated all
usages to reflect the new logic for improved clarity.
Refactored dark mode logic to first use user's ColorScheme
preference when "SystemBG" is set to "Auto". Only falls back
to system dark mode setting if ColorScheme is not explicitly
set to "Dark" or "Light". This ensures user preferences take
precedence over system defaults.
Freeze SolidColorBrush instances before assigning them to mainWindow.Background to improve performance and immutability. Applied to both transparent and selected background scenarios.
Replaces GetNewWindowBorderStyle with direct instantiation of a new Style for Border and uses CopyStyle to transfer properties. Removes the old helper method and moves style copying logic inline for improved clarity and maintainability.
Changed assignment of WindowBorderStyle to use Application.Current.Resources for global effect, replacing previous use of _oldResource. This ensures theme changes are applied consistently across the application.
@prlabeler prlabeler bot added Code Refactor enhancement New feature or request labels Mar 2, 2026
@Jack251970 Jack251970 changed the title Fix cast object of type 'System.Windows.Media.Color' to type 'System.Windows.Expression' exception Improve Theme.cs Mar 2, 2026
@Jack251970 Jack251970 removed bug Something isn't working enhancement New feature or request Code Refactor 10 min review labels Mar 4, 2026
@Jack251970 Jack251970 removed this from the 2.2.0 milestone Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants