Reputation: 3342
I am trying to display an image from a StorageFile
after selecting it from a FilePicker
. Since the Source
of an Image
has to be either a URI
or an ImageSource
, I am trying to get either of those from the StorageFile
.
I am having a hard time getting data binding to work on an Image
in XAML. I have tried the following:
<Image Width="300"
Height="300"
x:Name="LogoImage">
<Image.Source>
<BitmapImage UriSource="{Binding ImagePath}" />
</Image.Source>
</Image>
This way doesn't work, as the Path
property of a StorageFile
is not a URI
. Also, I can't bind directly to the StorageFile
itself, as it is not an ImageSource
.
I tried to use this method:
public async Task<Image> GetImageAsync(StorageFile storageFile)
{
BitmapImage bitmapImage = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read);
bitmapImage.SetSource(stream);
Image image = new Image();
image.Source = bitmapImage;
return image;
}
But, it returns a Task<Image>
, which is also not an ImageSource
or URI
. It seems like it should be something more straightforward than what I am trying to do, but I am just not seeing it. Also, I have tried just specifying a file in the XAML for the Image.Source
and it works fine. I just haven't been able to link it up based on the selected file from the FilePicker
.
My ultimate goal is: select a file from FilePicker
, update the ImageSource
of the displayed Image
, encode to base64 for storage in database. Then later, load existing base64 string from database, convert back to Image
to be displayed.
Edit:
I was able to accomplish this task using the solution I posted below. Thanks in great part to Jerry Nixon's blog post: http://blog.jerrynixon.com/2014/11/reading-and-writing-base64-in-windows.html
Upvotes: 0
Views: 1382
Reputation: 3342
If anyone else comes across this question looking for an answer, what I ultimately ended up doing for my situation, is take the StorageFile
that is selected from the FilePicker
, encode that as a base64 string (which I will save to my database for later retrieval).
Once I have the base64 string, I can decode that string into an ImageSource
to set in code-behind. Here is my full ButtonClick
event handler:
private async void ChooseImage_Click(object sender, RoutedEventArgs e)
{
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".jpg");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.SettingsIdentifier = "picker1";
filePicker.CommitButtonText = "Open File to Process";
var files = await filePicker.PickMultipleFilesAsync();
if (files.Count > 0)
{
// encode the storage file to base64
var base64 = await Encoding.ToBase64(files[0]);
// asynchronously save base64 string to database
// ...
// decode the base64 and set the image source
LogoImage.Source = await Encoding.FromBase64(base64);
}
}
The base64 encoding/decoding I found at the great Jerry Nixon's blog here: http://blog.jerrynixon.com/2014/11/reading-and-writing-base64-in-windows.html
Upvotes: 0
Reputation: 31724
The best solution would be to set the source in code behind instead of using a binding as it would let you handle things like cancellation in case the ImagePath gets updated while the previous image is still loading.
Alternatively, you could create a bitmap, start a task of loading it and return before that task is complete, e.g.
public Image GetImage(StorageFile storageFile)
{
var bitmapImage = new BitmapImage();
GetImageAsync(bitmapImage, storageFile);
// Create an image or return a bitmap that's started loading
var image = new Image();
image.Source = bitmapImage;
return image ;
}
private async Task GetImageAsync(BitmapImage bitmapImage, StorageFile storageFile)
{
using (var stream = (FileRandomAccessStream)await storageFile.OpenAsync(FileAccessMode.Read))
{
await bitmapImage.SetSource(stream);
}
}
Upvotes: 2