3

I have an ObservableCollection<Item> and an Item contains both a file path and an ImageSource of some image from the disk.

public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<MediaListItem>();
public class Item
{
    public string Image { get; set; } // Full path to the image
    public ImageSource ImageSource { get; set; }
}

However, I am unable to access any of the two attributes and display an image via XAML.

<ListView ItemsSource="{Binding MediaList}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Padding="10">
                    <Image Source="{Binding ImageSource}" VerticalOptions="Fill"></Image>
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Now I am confused because I am able to output the string Image via XAML through a label, but can't display an image from the path at all.

Anas Alweish
  • 2,818
  • 4
  • 30
  • 44
Bowser
  • 87
  • 1
  • 7

2 Answers2

3

You can use ImageSource.FromFile() or ImageSource.FromUri() like this

In Xaml

<Image  Source="{Binding  ImageSource}"  Aspect="AspectFit"  ></Image>

In Code

public ObservableCollection<Item> MediaList { get; set; } = new ObservableCollection<Item>()
        {
            new Item
            {
                ImageSource = ImageSource.FromFile("xamarin.png")
            },
            new Item
            {
                ImageSource = ImageSource.FromUri(new Uri("https://i.stack.imgur.com/4mMod.png"))
            }
        };

The result

enter image description here

Update

Depending on Microsoft-Local Images

Image files can be added to each application project and referenced from Xamarin.Forms shared code...

To use a single image across all apps, the same filename must be used on every platform, and it should be a valid Android resource name (ie. only lowercase letters, numerals, the underscore, and the period are allowed).

For more information take a look at the answer here

Now if you want to display an image without adding it to each platform, you should use Converter.

For example:

  1. Create a new folder called ImagesFolder in shared code then add the image to it

    enter image description here

  2. In Code, create a new class called ByteArrayToImageSourceConverter like this

    public class ByteArrayToImageSourceConverter : IValueConverter 
    {
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {   
        byte[] bytes;
        var assembly = GetType().GetTypeInfo().Assembly; // using System.Reflection;
    
        var stream = assembly.GetManifestResourceStream((string)value); // value = "App1.ImagesFolder.ninja.png"
        using (var ms = new MemoryStream()) // using System.IO; 
        {
            stream.CopyToAsync(ms);
            bytes = ms.ToArray();
        }
        return ImageSource.FromStream(() => new MemoryStream(bytes));
      }
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
        return null;
      }
    }
    

    View Model

    public ObservableCollection<Item> MediaList { get; set; } = new ObservableCollection<Item>()
    {
        new Item
        {
           Image  = "App1.ImagesFolder.ninja.png"
        }
    };
    
  3. In Xaml

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:App1"
         x:Class="App1.MainPage">
    
      <ContentPage.Resources>
        <ResourceDictionary>
           <local:ByteArrayToImageSourceConverter  x:Key="ByteArrayToImageSourceConverter" />
       </ResourceDictionary>
     </ContentPage.Resources>
    
     <ListView ItemsSource="{Binding MediaList}" >
        <ListView.ItemTemplate>
          <DataTemplate>
            <ViewCell>
               <Image Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}" />
            </ViewCell>
          </DataTemplate>
       </ListView.ItemTemplate>
     </ListView>
    
    </ContentPage>
    

Related Links

ByteArrayToImageSourceConverter

Shared Resources

How to load binary images in Xamarin?

Anas Alweish
  • 2,818
  • 4
  • 30
  • 44
1

Change ImageSource type to String

public class Item
{
    public string ImageSource { get; set; }
}

Usage

List<Item> items = new List<Item>();
items.Add(new Item() { ImageSource = "*THE URL OF IMAGE*" });
ListView.ItemsSource = items;
Ahmed Walid
  • 57
  • 2
  • 10
  • As you may see above, I had a string (path to the file) already, but that one doesn't work when using `Binding Image`, for whatever reason. In other words, whether I change it to a string or not, it's the same (as I already tried it). – Bowser May 26 '19 at 15:35
  • did you tried this code `List items = new List(); items.Add(new Item() { ImageSource = "*THE URL OF IMAGE*" }); ListView.ItemsSource = items;` – Ahmed Walid May 26 '19 at 15:38
  • you can use image from the disk by starting the path by `@"File://"` – Ahmed Walid May 26 '19 at 15:41
  • I concur with Ahmed's answer. I have a image path string property in vmodel as under that binds to Image in XAML: public string Text { get { return this.text; } set { this.text = value; this.OnPropertyChanged(nameof(Text)); } } – CloudArch Jun 05 '21 at 12:12