Reputation: 51
Information
Quite simply, I’m attempting to create an app that would display the contacts for a user.
I’m also a self-taught programmer, so I have experience with programming in some aspects, but I am relatively new to data-binding in general.
To begin, I have a ListView control that has an image binding within it.
<ListView x:Name="ContactsView" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<Image x:Name="ContactImage" Source="{Binding Converter={StaticResource ContactPictureConverter}, Mode=OneWay}" Height="100" Width="100" Margin="0,0,0,0"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I also have a converter that gets an IRandomAccessStream of the Contact Image and returns it as a BitmapImage. If no image is found (null exception), then the converter will return back a default picture for contacts.
public class ContactPictureConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string culture)
{
Contact c = value as Contact;
try
{
return GetImage(c).Result;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
return @"Images/default.jpg";
}
async Task<BitmapImage> GetImage(Contact con)
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.DecodePixelHeight = 100;
bitmapImage.DecodePixelWidth = 100;
using (IRandomAccessStream fileStream = await con.Thumbnail.OpenReadAsync())
{
await bitmapImage.SetSourceAsync(fileStream);
}
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, string culture)
{
throw new NotImplementedException();
}
}
Additional Information
The app is set for Windows Phone 8.1 WinRT.
To get the contacts, I use a ContactStore.
IReadOnlyList<Contact> contacts; //Global Declaration
ContactStore store = await ContactManager.RequestStoreAsync();
contacts = await store.FindContactsAsync();
ContactsView.ItemsSource = contacts;
Problem
Every contact is returning the default contact image (meaning some exception occurred when trying to get the contact image). This shouldn’t occur since majority of my contacts have images associated with them.
Question
How should I get the image of a contact and bind that to an image control within a ListView for Windows Phone 8.1?
Upvotes: 1
Views: 1139
Reputation: 11
public static BitmapImage GetImage(Contact con)
{
if (con == null || con.Thumbnail == null)
{
return null;
}
var bitmapImage = new BitmapImage();
bitmapImage.DecodePixelHeight = 256;
bitmapImage.DecodePixelWidth = 256;
Action load = async () =>
{
using (IRandomAccessStream fileStream = await con.Thumbnail.OpenReadAsync())
{
await bitmapImage.SetSourceAsync(fileStream);
}
};
load();
return bitmapImage;
}
Upvotes: 1
Reputation: 51
Thanks to Romasz and Murven, I was able to get a solution for my problem.
XAML:
<ListView x:Name="ContactsView" Grid.Row="1" Background="White" ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<Image x:Name="ContactImage" DataContext="{Binding Converter={StaticResource ContactPictureConverter}}" Source="{Binding Result}" Height="100" Width="100" Margin="0,0,0,0"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Converter:
using Nito.AsyncEx;
public class ContactPictureConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
try
{
Contact c = value as Contact;
return NotifyTaskCompletion.Create<BitmapImage>(GetImage(c));
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return null;
}
}
private async Task<BitmapImage> GetImage(Contact con)
{
using (var stream = await con.Thumbnail.OpenReadAsync())
{
BitmapImage image = new BitmapImage();
image.DecodePixelHeight = 100;
image.DecodePixelWidth = 100;
image.SetSource(stream);
return image;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string culture)
{
throw new NotImplementedException();
}
}
Packages:
Nito.AsyncEx from Nuget
Upvotes: 1
Reputation: 736
you can do one thing ..
you can retrieve all the images from the contacts class and store them in an array or stack or List of BitmapImages .. (*** i think list would be an better option )
Contact c = value as Contact;
foreach(var p in c)
{
q.Add(p.Thumbnail);
}
here q
is an list of bitmapmages
Upvotes: -1
Reputation: 2387
The problem is that the GetImage method is asynchronous, so you need to wait for the result to complete:
Task<BitmapImage> getImageTask = GetImage(c);
getImageTask.RunSynchronously();
return getImageTask.Result;
Upvotes: 0