WP 8.1 Binding image from a http request

2019-01-26 00:48发布

I have a ListView item which contains datas and images from a http GET request. I can display all of data in the ListView, except the picture. For getting the image I have to make a separate http GET request. I can display an image with this code:

private async void DisplayPicture()
{
    var ims = new InMemoryRandomAccessStream();
    var dataWriter = new DataWriter(ims);
    dataWriter.WriteBytes(App.answer.picture);
    await dataWriter.StoreAsync();
    ims.Seek(0);
    BitmapImage bitmap = new BitmapImage();
    bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
    bitmap.SetSource(ims);
}

But this doesn't work if I would like to use in a ListView with Binding. Here is the code what I tried:

public class BinaryToImageSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value != null && value is byte[])
        {
            var bytes = value as byte[];
            var ims = new InMemoryRandomAccessStream();
            var dataWriter = new DataWriter(ims);
            dataWriter.WriteBytes(bytes);
            //await dataWriter.StoreAsync();
            ims.Seek(0);
            BitmapImage bitmap = new BitmapImage();
            bitmap.SetSource(ims);
            //var ims = new MemoryStream(bytes);
            //var image = new BitmapImage();
            //image.SetSource(stream);
            //stream.Close();
            return bitmap;
        }
        return null;
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

The main problem is that I get the image in byte[] (bytearray) from the server, and only the above code can display it on WP8.1. So I have to use the dataWriter.StoreAsync() method, but if I use it, I have to use async, which must be void. But the void return value is not good for me due to the binding.

You can see the original code what I uncommented, but I cannot use it, because the input value for image.SetSource() must be a RandomAccessStream. So I don't have any idea how I can solve this problem.

1条回答
不美不萌又怎样
2楼-- · 2019-01-26 01:04

If you want to make binding and use asynchronous method, then one way to make it work is to set DataContext to Task and bind to its Result. Stepen Cleary wrote a nice article about that. You will also find some useful information in his answer here.

Basing on that answer I've build a sample, which I think you can modify to fulfill your needs. Write a Converter which will return TaskCompletionNotifier (see Stephen's answer above):

public class WebPathToImage : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null) return null;
        // the below class you will find in Stephen's answer mentioned above
        return new TaskCompletionNotifier<BitmapImage>(GetImage((String)value));
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    { throw new NotImplementedException(); }

    private async Task<BitmapImage> GetImage(string path)
    {
        HttpClient webCLient = new HttpClient();
        var responseStream = await webCLient.GetStreamAsync(path);
        var memoryStream = new MemoryStream();
        await responseStream.CopyToAsync(memoryStream);
        memoryStream.Position = 0;
        var bitmap = new BitmapImage();
        await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream());
        return bitmap;
    }
}

then you can define binding in XAML:

<Image DataContext="{Binding ImageFromWeb, Converter={StaticResource WebPathToImage}}" Stretch="Uniform" 
       Source="{Binding Result}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="2"/>

Everything should work when you set ImageFromWeb:

ImageFromWeb = @"http://www.onereason.org/wp-content/uploads/2012/02/universe-300x198.jpg";
查看更多
登录 后发表回答