Skip to content

Fall back to the solid color when the background image can't load#150

Merged
danielchalmers merged 1 commit into
masterfrom
fix/background-image-fallback
Jul 11, 2026
Merged

Fall back to the solid color when the background image can't load#150
danielchalmers merged 1 commit into
masterfrom
fix/background-image-fallback

Conversation

@danielchalmers

@danielchalmers danielchalmers commented Jul 11, 2026

Copy link
Copy Markdown
Owner

When a background image is set and then becomes unreadable — the file is deleted, moved, replaced with a non-image file (the picker offers an "All files" filter), or lives on an unavailable network share — the ImageBrush fails to load, WPF swallows the error, and the brush paints nothing. The clock is left with a fully transparent background and no outline, so e.g. white text sits directly on the desktop with no backing and can be unreadable.

The existing solid-color fallback only triggered when the path was empty, so a set-but-broken path fell through to a blank background.

Fixed by building the background brush through a small IMultiValueConverter (BackgroundBrushConverter) instead of the style triggers:

  • Background off → transparent (outlined-text mode), unchanged.
  • Background on, image loads → ImageBrush, exactly as before.
  • Background on, image missing / non-image / unreadable / empty path → solid OuterColor.

The image is loaded with BitmapCacheOption.OnLoad inside a try/catch, so a bad file fails predictably (and the file isn't held open). A valid image renders identically to before, including transparent gaps with Uniform/None stretch.

Case Before After
Valid image image image (unchanged)
Missing file no background solid color
Non-image file no background solid color
Empty path solid color solid color (unchanged)
Background disabled transparent + outline transparent + outline (unchanged)

If a background image was set and then deleted, moved, replaced with a
non-image file, or put on an unavailable share, the ImageBrush failed
silently and the clock rendered with no background at all - unreadable text
on the bare desktop. The empty-path solid-color fallback never applied
because the path wasn't empty. Build the background through a converter that
tries the image and falls back to the solid outer color whenever it can't be
loaded; a valid image still renders exactly as before.
@github-actions github-actions Bot added the bug Something isn't working label Jul 11, 2026
@danielchalmers
danielchalmers requested a review from Copilot July 11, 2026 12:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a WPF rendering gap where a configured-but-unloadable background image results in a fully transparent clock background, by centralizing brush creation logic into a converter that can reliably fall back to a solid color.

Changes:

  • Added BackgroundBrushConverter to build the background brush and fall back to OuterColor when image loading fails.
  • Replaced Border style triggers in MainWindow.xaml with a MultiBinding to the new converter.

Reviewed changes

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

File Description
DesktopClock/Utilities/BackgroundBrushConverter.cs Introduces an IMultiValueConverter that attempts to load the background image eagerly and falls back to a solid brush when loading fails.
DesktopClock/MainWindow.xaml Switches background selection logic from XAML triggers to a MultiBinding using the new converter.

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

Comment on lines +59 to +63
catch
{
// Missing file, non-image content, unavailable share, or a malformed path all fall back to the solid color.
return null;
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Keeping the bare catch here, deliberately:

  • It matches the intent exactly. The contract is "if the image can't be produced for any reason, fall back to the solid color" — the same all-or-nothing semantics the previous XAML binding had (WPF's binding engine swallowed every load failure silently). Enumerating exception types just risks missing one (UriFormatException, FileNotFoundException, NotSupportedException, IOException, UnauthorizedAccessException, ArgumentException are all reachable from this block) and turning a bad path into a crash on someone's machine.
  • It's the established pattern in this codebase — e.g. Tokenizer.FormatWithTokenizerOrFallBack, Settings.Save/LoadFromFile/FileChanged, MainWindow.CopyToClipboard/TryPlaySound, ThemeManager.ApplyTitleBarTheme all use bare catch for graceful fallback. A critical-exception filter here would be the only one of its kind.
  • The critical-exception concern is mostly theoretical on net481: ThreadAbortException automatically re-throws at the end of a catch block, and a process-fatal OOM won't be meaningfully rescued by one converter propagating it.

If the project ever adopts a repo-wide exception-filter convention this spot should follow it, but I don't think this PR is the place to introduce a one-off.

@danielchalmers
danielchalmers merged commit f6186d9 into master Jul 11, 2026
6 checks passed
@danielchalmers
danielchalmers deleted the fix/background-image-fallback branch July 11, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants