I have a form to fill in with data including an image which then goes into a listview. When I click on a button to get an image it works and it goes into the form, however when I click on another button to add it to the listview, the error [System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'Stream has been closed'] appears.
Thanks for your help
When I press the add image button :
var ActionPhoto = await DisplayActionSheet("Ajouter une pièce-jointe depuis:", "Annuler", null, "Galerie", "Caméra");
switch (ActionPhoto)
{
case "Galerie":
var Galerie = await MediaPicker.PickPhotoAsync(new MediaPickerOptions { Title = "Choisir une image" });
if (Galerie != null)
{
var voirImageGalerie = await Galerie.OpenReadAsync();
Image_Photos.Source = ImageSource.FromStream(() => voirImageGalerie);
}
break;
case "Caméra":
var camera = await MediaPicker.CapturePhotoAsync();
if (camera != null)
{
var voirImageCamera = await camera.OpenReadAsync();
Image_Photos.Source = ImageSource.FromStream(() => voirImageCamera);
}
break;
}
When I press the add button of the listView:
App.listePosteNoteFrais.Add(new Data{PostePJ = Image_Photos.Source});
In my Data Class:
public ImageSource PostePJ { get; set; }
What I'm adding to my listview:
<Image x:Name="Image_PostePJ" Source="{Binding PostePJ}" HeightRequest="150" WidthRequest="150" Grid.Row="0" Grid.Column="12"/>
CodePudding user response:
Given code:
ImageSource.FromStream(() => voirImageCamera)
The parameter to FromStream
:
() => voirImageCamera
is executed every time the image is needed.
The exception message:
System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'Stream has been closed.
Is telling you that the stream (voirImageCamera
) is no longer useable.
I'm not sure what internal code is disposing that stream. Maybe MediaPicker thinks its no longer needed. Or maybe its due to copying from one image source to another. Or something about how/when ListView accesses the image source.
As seen in doc Xamarin.Essentials: Media Picker / General Usage, a safe way to use a result from MediaPicker's OpenReadAsync
, is to save the stream in a local file, then use that file as the image source:
// save the file into local storage
var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
using (var stream = await photo.OpenReadAsync())
using (var newStream = File.OpenWrite(newFile))
await stream.CopyToAsync(newStream);
Then set the image source to that file:
Image_Photos.Source = ImageSource.FromFile(newFile);
The advantage of FromFile
, is that it should be able to open the file at any time it needs - there is no stream
being held open.
NOTE: The doc example uses CacheDirectory
. Depending on the situation, FileSystem.AppDataDirectory
might be more appropriate (files that should be kept indefinitely).