0

I am trying to add an image from the device to my App in Xamarin using https://github.com/jamesmontemagno/MediaPlugin. The odd thing is, that adding the Item raises an exeption at some point "between the lines". I don't know how to debug this and assume it happens implementing OnPropertyChanged wrong.

I wrapped the exeption in a Try/Catch Block and to my surprise learned that the Item has actually been added and App.api.message.MediaFiles.Count() has increased. This leads me to assume that the Exeption actually happes after but not at .Add(Item).

This must either be the OnPropertyChanged() (But then why is the Debugger not showhing me that portion of code?) or the magic behind the scenes where Xamarin binds the Listview to ...Thumbnail.

However since both of these options are relatively new to me a mistake or misinterpretation is quite likely here and any hint on how or where to investigate this would be appreciated.

Here's what I do in detail:

 [...]
    public MainPage()
    {
        InitializeComponent();
        BindingContext = App.api.message;
        Media.ItemsSource = App.api.message.MediaFiles;
      [...]
    }

The Listview in XAML :

[...]
<ListView x:Name="Media" BackgroundColor="#f1f1f1" HasUnevenRows="true" IsVisible="true" Header="Media" ItemTapped="RemoveImage" RowHeight="90" HeightRequest="120">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding thumbnail}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView> 
[...]

With file comming from picking or taking an image I do:

    public void AddFile(MediaFile file)
    { 
        Classes.MessageClass.Media Item = new Classes.MessageClass.Media();

        Item.Filename = file.Path;

        Item.Thumbnail = ImageSource.FromStream(() =>
        {
            var stream = file.GetStreamWithImageRotatedForExternalStorage();
            return stream;
        });

        file.Dispose();

        FileInfo fileInfo = new FileInfo(Item.Filename);
        Item.Size = fileInfo.Length;

        Console.WriteLine("\n\nOriginal File:{0} \n{1:###,###,###} Bytes\nCaption: {2}\nContent Type: {3}", Item.Filename, Item.Size, Item.Caption,Item.ContentType);

        try
        {
            App.api.message.MediaFiles.Add(Item);  //EXEPTION "Specified cast not Valid"
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exeption: " + ex.Message + " " + ex.Data.Values.ToString());
        }
        Console.WriteLine("Attached Images: " + App.api.message.MediaFiles.Count());
        App.api.message.HasMedia = true;

        UpdateImagesUI();
    }

And finally my definition of Classes.MessageClass.Media. (I added values to outrule null-value issues):

public class Media
    {
        public string Caption { get; set; } = "";
        public string Filename { get; set; } = "";
        ImageSource thumbnail;
        public long Size { get; set; } = 0;
        public string ContentType { get; set; } = "";
        public bool IsVideo { get; set; } = false;
        public ImageSource Thumbnail
        {
            get
            { 
                return thumbnail;
            }
            set 
            { 
                if ((thumbnail != value) && (value != null))
                {
                    thumbnail = value;
                    Console.WriteLine("Image Updated");
                    OnPropertyChanged("Thumbnail");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            var changed = PropertyChanged;
            if (changed != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

And in MessageClass(): MediaFiles = new ObservableCollection<Media>();

Finally the Stack:

 (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x0000f] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:288 
 at  System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:351 
 at System.Collections.ObjectModel.ObservableCollection`1[T].InsertItem (System.Int32 index, T item) [0x00024] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/mcs/class/referencesource/System/compmod/system/collections/objectmodel/observablecollection.cs:219 
 at System.Collections.ObjectModel.Collection`1[T].Add (T item) [0x00020] in /Library/Frameworks/Xamarin.iOS.framework/Versions/12.0.0.15/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/collections/objectmodel/collection.cs:67 
 at SegelnBlogsEditor.MainPage.AddFile (Plugin.Media.Abstractions.MediaFile file) [0x0009e] in /Users/hinnerkweiler/wwwroot/SegelnBlogsEditor/SegelnBlogsEditor/MainPage.xaml.cs:292

1 Answers1

0

ImageSource.FromStream method takes an Action as parameter, which is evaluated every-time the ViewCell needs to be rendered. Using the file reference inside the action for later use and disposing it would cause exceptions.

Edit:

A better approach would be getting Image from file name

Image.Thumbnail = ImageSource.FromFile(Item.Filename);
memsranga
  • 1,088
  • 7
  • 13
  • Just for clearification. Does that mean in `Item.Thumbnail = ImageSource.FromStream(() ...` I am not returning the `stream` content to the property but the Action itself? – Hinnerk Weiler Oct 16 '18 at 08:23
  • `ImagSource.FromStream` evaluates the Action and returns the stream. But the `file` object is already disposed, which case it throws exception, check the [MediaPlugin Source](https://github.com/jamesmontemagno/MediaPlugin/blob/master/src/Media.Plugin/Shared/MediaFile.cs#L77) – memsranga Oct 16 '18 at 08:58
  • Ok, I see that point. I actually turned to `Image.Thumbnail = ImageSource.FromFile(Item.Filename);`- originally as a work around because that way I risk to show a bunch of 50MB Images as thumbnails. Thank alot for point me to further readings. – Hinnerk Weiler Oct 16 '18 at 09:36
  • Also, I'd suggest you take a look at [FFImageLoading](https://github.com/luberda-molinet/FFImageLoading) library – memsranga Oct 16 '18 at 09:42