Skip to content

Commit cab41cc

Browse files
mohnjilesclaude
andcommitted
Image viewer: construct ImageSource from bitmap to bypass Task binding race
The viewer's template selector binds to ImageSource.TemplateKey via a Task-based async binding (TemplateKeyAsync^). On the first read the Task is pending and the binding returns default(ImageSourceTemplateType) = Default, which is mapped to a "Unsupported Format" text template. The selector doesn't re-pick when the Task completes later, so the "unsupported" text sticks around even though TemplateKey eventually resolved to Image. The previous fix (await GetOrRefreshTemplateKeyAsync before assigning) didn't help because TemplateKeyAsync returns a *fresh* Task on every access — pre-resolving the underlying field still goes through a new Task at binding time. Switch to ImageSource's bitmap-only constructor, which sets TemplateKey = Image synchronously in the ctor body. AdvancedImageBox renders the decoded bitmap regardless of whether the bytes were JPEG, PNG, or WebP, which is exactly what we need for CivArchive's extensionless CDN URLs (img.genur.art/sig/.../base64). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b6f12d3 commit cab41cc

1 file changed

Lines changed: 11 additions & 8 deletions

File tree

StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivArchiveDetailsPageViewModel.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -462,19 +462,22 @@ private async Task ShowImageDialog(CivArchiveModelImage? image)
462462
}
463463

464464
/// <summary>
465-
/// Build an <see cref="ImageSource"/> ready for the image viewer to render. Critically,
466-
/// <see cref="ImageSource.GetOrRefreshTemplateKeyAsync"/> must run before assigning so the
467-
/// viewer's template selector picks the right control for animated WebPs vs static images
468-
/// — otherwise navigation to certain images shows "Unsupported format".
465+
/// Build an <see cref="ImageSource"/> ready for the image viewer to render.
466+
/// The viewer's template selector keys off <c>ImageSource.TemplateKey</c>; if that's
467+
/// <c>Default</c>, the selector renders the literal "Unsupported Format" text. The
468+
/// URL-construction path leaves TemplateKey as Default until a Task-based binding
469+
/// resolves it, which races with the viewer's first paint on extensionless CivArchive
470+
/// CDN URLs (e.g. <c>img.genur.art/sig/.../base64</c>). Use the bitmap-only constructor
471+
/// instead — it sets TemplateKey to Image synchronously, which the AdvancedImageBox
472+
/// can render whether the bytes were JPEG, PNG, or WebP.
469473
/// </summary>
470474
private static async Task<ImageSource?> PrepareImageSourceAsync(string url)
471475
{
472476
try
473477
{
474-
var source = new ImageSource(new Uri(url));
475-
await source.GetBitmapAsync();
476-
await source.GetOrRefreshTemplateKeyAsync();
477-
return source;
478+
var loader = new ImageSource(new Uri(url));
479+
var bitmap = await loader.GetBitmapAsync();
480+
return bitmap is not null ? new ImageSource(bitmap) { RemoteUrl = new Uri(url) } : null;
478481
}
479482
catch
480483
{

0 commit comments

Comments
 (0)