.NET MAUI image from source in collection view is not working on IOS, while fine working on Android emulator and Windows.
I am trying to load byte[] array from SQLite database, then convert it to memory stream and after equalize to ImageSource in order to add Image to ObservableCollection and display in CollectionView. It works well on Android Emulator and on Windows. There are not appearing any errors.
Here are images of the problem. How it looks on Windows
https://drive.google.com/file/d/1ymXVjoTIzRkhP9rHe50_9rLj3h6jHbZ_/view?usp=sharing
https://drive.google.com/file/d/1I5sPPMtemUK4vEp8kODZZNljy5pdKA-w/view?usp=sharing
How it looks on IOS
https://drive.google.com/file/d/1VUIrKHJ7cR_AKxRYDRcgKON9SA-L60z5/view?usp=sharing
Here are my snippets of code:
ViewModel
using PlumbingCompany.Services;
using PlumbingCompany.Models;
namespace PlumbingCompany.Data;
public partial class Page2ViewModel : ObservableObject
{
private readonly IJobService _jobService;
public Page2ViewModel(IJobService jobService)
{
_jobService = jobService;
ID = GlobalVariables.CurrentID;
GetPhotoList(ID);
}
[ObservableProperty]
private Page2Data _Page2Data = new Page2Data();
[ObservableProperty]
private ImageSource imageSource;
[ObservableProperty]
private string _Name;
[ObservableProperty]
private string _ImageData;
[ObservableProperty]
private byte[] _Bytes;
[ObservableProperty]
int _ID;
public ObservableCollection<Page2Data> ImagesCollection { get; private set; } = new
ObservableCollection<Page2Data>();
public List<Page2Data> ImagesList { get; set; } = new List<Page2Data>();
[RelayCommand]
public async void GetPhotoList(int ID)
{
ImagesCollection.Clear();
var imageList = await _jobService.GetImagesList(ID);
if (imageList?.Count > 0)
{
imageList = imageList.ToList();
foreach (var image in imageList)
{
MemoryStream ms = new MemoryStream(image.Bytes);
Page2Data = image;
Page2Data.imageSource = ImageSource.FromStream(() => ms);
ImagesCollection.Add(Page2Data);
}
ImagesList.Clear();
ImagesList.AddRange(imageList);
ImagesSaved = ImagesList.Count();
}
else ImagesSaved = 0;
}
}
Model
using SQLite;
using System.ComponentModel.DataAnnotations.Schema;
namespace PlumbingCompany.Models
{
[SQLite.Table("Page2Data")]
public class Page2Data
{
[PrimaryKey, AutoIncrement]
public int Image_Id { get; set; }
public string Name { get; set; }
public string ImageSource { get; set; }
public int Id { get; set; }
public byte[] Bytes { get; set; }
public string RowID { get; set; }
[NotMapped]
public string Bytes64 { get; set; }
[Ignore]
public ImageSource imageSource { get; set; }
}
}
View
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PlumbingCompany.Views.Page2_PhotoUpload"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:viewModels="clr-namespace:PlumbingCompany.Data"
xmlns:Models="clr-namespace:PlumbingCompany.Models"
x:DataType="viewModels:Page2ViewModel"
Title="2. Photo upload">
...
<ScrollView Orientation="Vertical" MinimumHeightRequest="500">
<ScrollView Orientation="Horizontal">
<StackLayout Padding="10">
<CollectionView x:Name="ImageListView" ItemsSource="{Binding ImagesCollection}" >
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame Margin="10" Padding="10" MinimumHeightRequest="300" MaximumHeightRequest="500">
<HorizontalStackLayout Spacing="50">
<Image
Source= "{Binding ImageSource }"
Aspect="AspectFit"
MaximumHeightRequest="1024"
MinimumHeightRequest="300"
MaximumWidthRequest="768"
MinimumWidthRequest="300"/>
<VerticalStackLayout>
<Label
Text="{Binding Name}"
LineBreakMode="CharacterWrap"
FontAttributes="Bold"
VerticalOptions="End"
Padding="15"
HorizontalOptions="EndAndExpand"/>
<Button
Text="Delete"
TextColor="White"
Background="#9B082B"
Margin="0,20,0,0"
HorizontalOptions="Start"
VerticalOptions="Start"
Command="{Binding Path=BindingContext.DeleteImageButtonTypedCommand, Source={x:Reference ImageListView}}"
CommandParameter="{Binding .}"
/>
</VerticalStackLayout>
</HorizontalStackLayout>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ScrollView>
</ScrollView >
...
</ContentPage>
View C# Background File
using PlumbingCompany.Data;
namespace PlumbingCompany.Views;
public partial class Page2_PhotoUpload : ContentPage
{
public Page2_PhotoUpload(Page2ViewModel viewModel)
{
BindingContext = viewModel;
InitializeComponent();
}
}
Service File
using SQLite;
using PlumbingCompany.Models;
namespace PlumbingCompany.Services
{
public class JobService : IJobService
{
private SQLiteAsyncConnection _dbConnection;
private async Task SetUpDb()
{
...
}
public async Task<int> AddImage(Page2Data page2Data)
{
return await _dbConnection.InsertAsync(page2Data);
}
public async Task<List<Page2Data>> GetImagesList(int ID)
{
var page2Data = await _dbConnection.Table<Page2Data>().Where(i => i.Id == ID).ToListAsync();
return page2Data;
}
IService
using PlumbingCompany.Models;
namespace PlumbingCompany.Services
{
public interface IJobService
{
Task SetUpDataBase();
Task<int> AddImage(Page2Data page2Data);
Task<int> DeleteImage(Page2Data page2Data);
Task<List<Page2Data>> GetImagesList(int ID);
}
}
How it looks in SQLite database viewer
https://drive.google.com/file/d/1wUQa998JeYMGYnqgfiFA3LZSEdC5bkrh/view?usp=sharing
Also I tried to use NUGET CommunityToolkit package's converter called "ByteArrayToImageSourceConverter" and result was the same: everything worked fine on android emulator and Windows, but not on IOS device.(It also displayed empty places instead of photos on IOS)