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 Task? _captureImagesTask = null;
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<KeyValuePair<IImage, ImageRecord>> _images = new();
|
[ObservableProperty] private ObservableCollection<AsyncImageRecordViewModel> _images = new();
|
||||||
[ObservableProperty] private bool _imagesIsCapturing = false;
|
[ObservableProperty] private bool _imagesIsCapturing = false;
|
||||||
[ObservableProperty] private string _imagesCapturingProgress = "";
|
[ObservableProperty] private string _imagesCapturingProgress = "";
|
||||||
[ObservableProperty] private int _imagesSectionCurrentIndex = 0;
|
[ObservableProperty] private int _imagesSectionCurrentIndex = 0;
|
||||||
@@ -88,12 +88,16 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
|||||||
partial void OnEditingRecordChanged(SeparatorRecord value)
|
partial void OnEditingRecordChanged(SeparatorRecord value)
|
||||||
{
|
{
|
||||||
var images = value.Images
|
var images = value.Images
|
||||||
.ToAsyncEnumerable()
|
.Select(i =>
|
||||||
.Select(i => new KeyValuePair<string?, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "separator"), i))
|
{
|
||||||
.Where(kv => kv.Key is not null)
|
var path = _imageStorageService.GetFullPath(i.ImagePath, "separator");
|
||||||
.Select(kv => new KeyValuePair<IImage, ImageRecord>(new Bitmap(kv.Key!), kv.Value));
|
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;
|
[RelayCommand] private void ToggleMenu() => IsMenuOpen = !IsMenuOpen;
|
||||||
@@ -277,10 +281,14 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
|||||||
_illuminatorService.TurnOff();
|
_illuminatorService.TurnOff();
|
||||||
|
|
||||||
var images = imageRecords
|
var images = imageRecords
|
||||||
.ToAsyncEnumerable()
|
.Select(i =>
|
||||||
.Select(i => new KeyValuePair<string?, ImageRecord>(_imageStorageService.GetFullPath(i.ImagePath, "separator"), i))
|
{
|
||||||
.Where(kv => kv.Key is not null)
|
var path = _imageStorageService.GetFullPath(i.ImagePath, "separator");
|
||||||
.Select(kv => new KeyValuePair<IImage, ImageRecord>(new Bitmap(kv.Key!), kv.Value));
|
if (path is null)
|
||||||
|
return null;
|
||||||
|
return new AsyncImageRecordViewModel(path, i);
|
||||||
|
})
|
||||||
|
.OfType<AsyncImageRecordViewModel>();
|
||||||
|
|
||||||
Dispatcher.UIThread.Invoke(() =>
|
Dispatcher.UIThread.Invoke(() =>
|
||||||
{
|
{
|
||||||
@@ -288,7 +296,7 @@ public partial class AmineContentSeparatorCalibrationViewModel : ViewModelBase
|
|||||||
EditingRecord.Images.AddRange(imageRecords);
|
EditingRecord.Images.AddRange(imageRecords);
|
||||||
|
|
||||||
Images.Clear();
|
Images.Clear();
|
||||||
Images = new(images.ToBlockingEnumerable());
|
Images = new(images);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -272,14 +272,33 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<core:ZoomPanImage
|
<Grid
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.RowSpan="11"
|
Grid.RowSpan="11"
|
||||||
Grid.Column="0"
|
Grid.Column="0">
|
||||||
|
|
||||||
|
<core:ZoomPanImage
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Background="Black"
|
Background="Black"
|
||||||
ImageSource="{Binding Key}" />
|
ImageSource="{Binding Image}"
|
||||||
|
IsVisible="{Binding IsLoading, Converter={x:Static BoolConverters.Not}}" />
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding IsLoading}">
|
||||||
|
|
||||||
|
<ProgressBar IsIndeterminate="True" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
FontSize="18"
|
||||||
|
Text="Изображение загружается" />
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
@@ -291,7 +310,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Classes="singleline"
|
Classes="singleline"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Text="{Binding Value.Id}" />
|
Text="{Binding ImageRecord.Id}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -303,7 +322,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Classes="singleline"
|
Classes="singleline"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Text="{Binding Value.ImagePath}" />
|
Text="{Binding ImageRecord.ImagePath}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
@@ -315,7 +334,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Classes="singleline"
|
Classes="singleline"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Text="{Binding Value.VisibleIntensity}" />
|
Text="{Binding ImageRecord.VisibleIntensity}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="6"
|
Grid.Row="6"
|
||||||
@@ -327,7 +346,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Classes="singleline"
|
Classes="singleline"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Text="{Binding Value.Uv365Intensity}" />
|
Text="{Binding ImageRecord.Uv365Intensity}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
@@ -339,7 +358,7 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Classes="singleline"
|
Classes="singleline"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Text="{Binding Value.Uv254Intensity}" />
|
Text="{Binding ImageRecord.Uv254Intensity}" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -389,13 +408,20 @@
|
|||||||
|
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsVisible="{Binding ImagesIsCapturing}">
|
||||||
|
|
||||||
|
<ProgressBar IsIndeterminate="True" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="18"
|
FontSize="18"
|
||||||
IsVisible="{Binding ImagesIsCapturing}"
|
|
||||||
Text="{Binding ImagesCapturingProgress}" />
|
Text="{Binding ImagesCapturingProgress}" />
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- Кнопки -->
|
<!-- Кнопки -->
|
||||||
|
|||||||
Reference in New Issue
Block a user