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.
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.sstatic.net/4mMod.png"))
}
};
The result
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:
Create a new folder called ImagesFolder
in shared code then add the image to it
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"
}
};
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