using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; namespace GSS2.UI.Core.ViewModels; public partial class AsyncImageRecordViewModel : ViewModelBase { private static readonly SemaphoreSlim _semaphore = new(1, 1); [ObservableProperty] public partial string? Data { get; set; } [ObservableProperty] public partial IImage? Image { get; set; } [ObservableProperty] public partial bool IsLoading { get; set; } = false; public AsyncImageRecordViewModel(string? data = null) { Data = data; } partial void OnDataChanged(string? value) => _ = LoadAsync(); private async Task LoadAsync() { await _semaphore.WaitAsync(); try { if (Data is not null) { IsLoading = true; byte[] imageBytes = Convert.FromBase64String(Data); Bitmap bitmap; using (var stream = new MemoryStream(imageBytes)) { bitmap = await Task.Run(() => new Bitmap(stream)); } await Dispatcher.UIThread.InvokeAsync(() => { Image = bitmap; IsLoading = false; }); } else { Image = new WriteableBitmap(new Avalonia.PixelSize(1, 1), new Avalonia.Vector(96, 96), Avalonia.Platform.PixelFormat.Bgra8888, Avalonia.Platform.AlphaFormat.Premul); } } catch { await Dispatcher.UIThread.InvokeAsync(() => IsLoading = false); } finally { _semaphore.Release(); } } }