forked from amkovkov/GranuSightSoftware2
feat: safe image loading
add AsyncImageViewModel that loading images sequentially
This commit is contained in:
@@ -39,7 +39,7 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
||||
|
||||
[ObservableProperty] private Task? _captureImagesTask = null;
|
||||
|
||||
[ObservableProperty] private ObservableCollection<KeyValuePair<IImage, ImageRecord>> _images = new();
|
||||
[ObservableProperty] private ObservableCollection<AsyncImageRecordViewModel> _images = new();
|
||||
[ObservableProperty] private bool _imagesIsCapturing = false;
|
||||
[ObservableProperty] private string _imagesCapturingProgress = "";
|
||||
[ObservableProperty] private int _imagesSectionCurrentIndex = 0;
|
||||
@@ -88,12 +88,16 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
||||
partial void OnEditingRecordChanged(SeparatorRecord value)
|
||||
{
|
||||
var images = value.Images
|
||||
.ToAsyncEnumerable()
|
||||
.Select(i => new KeyValuePair<string?, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "separator"), i))
|
||||
.Where(kv => kv.Key is not null)
|
||||
.Select(kv => new KeyValuePair<IImage, ImageRecord>(new Bitmap(kv.Key!), kv.Value));
|
||||
.Select(i =>
|
||||
{
|
||||
var path = _imageStorageService.GetFullPath(i.ImagePath, "separator");
|
||||
if (path is null)
|
||||
return null;
|
||||
return new AsyncImageRecordViewModel(path, i);
|
||||
})
|
||||
.OfType<AsyncImageRecordViewModel>();
|
||||
|
||||
Images = new(images.ToBlockingEnumerable());
|
||||
Images = new(images);
|
||||
}
|
||||
|
||||
[RelayCommand] private void ToggleMenu() => IsMenuOpen = !IsMenuOpen;
|
||||
@@ -277,10 +281,14 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
||||
_illuminatorService.TurnOff();
|
||||
|
||||
var images = imageRecords
|
||||
.ToAsyncEnumerable()
|
||||
.Select(i => new KeyValuePair<string?, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "separator"), i))
|
||||
.Where(kv => kv.Key is not null)
|
||||
.Select(kv => new KeyValuePair<IImage, ImageRecord>(new Bitmap(kv.Key!), kv.Value));
|
||||
.Select(i =>
|
||||
{
|
||||
var path = _imageStorageService.GetFullPath(i.ImagePath, "separator");
|
||||
if (path is null)
|
||||
return null;
|
||||
return new AsyncImageRecordViewModel(path, i);
|
||||
})
|
||||
.OfType<AsyncImageRecordViewModel>();
|
||||
|
||||
Dispatcher.UIThread.Invoke(() =>
|
||||
{
|
||||
@@ -288,7 +296,7 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
||||
EditingRecord.Images.AddRange(imageRecords);
|
||||
|
||||
Images.Clear();
|
||||
Images = new(images.ToBlockingEnumerable());
|
||||
Images = new(images);
|
||||
});
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
|
||||
using GSS2.Core.Analysis.AmineContent.Database.Calibration;
|
||||
|
||||
namespace GSS2.UI.Core.ViewModels;
|
||||
|
||||
public partial class AsyncImageRecordViewModel : ViewModelBase
|
||||
{
|
||||
private static readonly SemaphoreSlim _semaphore = new(1, 1);
|
||||
|
||||
private readonly string _path;
|
||||
|
||||
[ObservableProperty] private ImageRecord _imageRecord;
|
||||
[ObservableProperty] private IImage? _image;
|
||||
[ObservableProperty] private bool _isLoading = true;
|
||||
|
||||
public AsyncImageRecordViewModel(string path, ImageRecord imageRecord)
|
||||
{
|
||||
_path = path;
|
||||
_imageRecord = imageRecord;
|
||||
_ = LoadAsync();
|
||||
}
|
||||
|
||||
private async Task LoadAsync()
|
||||
{
|
||||
await _semaphore.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var bitmap = await Task.Run(() => new Bitmap(_path));
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
Image = bitmap;
|
||||
IsLoading = false;
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(() => IsLoading = false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_semaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user