Асинхронная загрузка Bitmap в Carousel
Я столкнулся с проблемой того, что я не могу понять, как загружать Bitmap
асинхронно в Carousel
в Avalonia. Если я правильно понял, то для этого нужно использовать ObservableCollection<>
и в XAML использовать {Binding ...^}
для того, чтобы указать на асинхронность выполнения.
Если для простого Image
можно использовать Task<Bitmap>
и все прекрасно работает, то Carousel
представляет собой ItemControl
и в него надо сувать коллекцию, но если я так делаю (вне зависимости от того простой это Bitmap
или Task<Bitmap>
), то компилятор выдает исключение (NRE).
Это абстрактный пример класса
private ObservableCollection<Task<Bitmap?>> _gallery;
private Task<Bitmap?> _poster;
var poster = Utility.LoadFromWeb("https://place.abh.ai/s3fs-public/placeholder/DSC_0089_400x400.JPG");;
Poster = poster;
Gallery = [poster, poster, poster];
А в XAML это выглядит как-то так
<Image ... Source="{Binding Poster^}"/>
<Carousel ... ItemsSource="{Binding Gallery^}"/>
Загрузчик фото выглядит стандартно (из примера документации)
using var httpClient = new HttpClient();
try
{
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var data = await response.Content.ReadAsByteArrayAsync();
return new Bitmap(new MemoryStream(data));
}
catch (HttpRequestException ex)
{
Console.WriteLine($"An error occurred while downloading image '{url}' : {ex.Message}");
return null;
}
Ответы (1 шт):
Всё оказалось проще, чем я думал. В частности, мои ошибки:
- Я помещал в коллекцию не
Image
, аBitmap
(может, можно иBitmap
, я не проверял, потом отредактирую). - Мой парсер возвращал не прямую ссылку на фото, поэтому
MemoryStream
выдавал исключение (я думал это из-за асинхронности). - Для тега
Image
нужно ставить^
для асинхронности, дляCarousel
в этом нет необходимости, потому чтоObservableCollection
и без этого справляется.
Пример для потомков (Avalonia + ReactiveUI):
Свойства, где хранится наша галерея:
private ObvservableCollection<Image> _gallery = [];
public ObservableCollection<Image> Gallery
{
get => _gallery;
set => this.RaiseAndSetIfChanged(ref _gallery, value);
}
Последовательная загрузка:
var links = new List<string>() { "ссылка", "ссылка" };
foreach (var link in links)
{
var image = new Image
{
Source = await Utility.LoadFromWeb(link)
};
Gallery.Add(image);
}
Паралелльная загрузка:
var links = new List<string>() { "ссылка", "ссылка" };
var tasks = links.Select(async link => new Image { Source = await Utility.LoadFromWeb(link) });
var images = await Task.WhenAll(tasks);
Gallery = new ObservableCollection<Image>(images);
И все работает, код для загрузки изображения доступен выше.