Reputation: 568
I have a WinRT app that takes pictures and displays them in an Image. The first picture correctly takes and displays the Image. However, subsequent pictures, which are set to overwrite the original picture, throw an UnauthorizedAccessException
with ACCESSDENIED
. I'm also binding the Image source to the Uri of the student. I'm also positive the binding is what is causing the issue in that WinRT doesn't like me replacing a file that is currently in use. I've tried setting the source to null before the file replace, etc, but that is not working. What is an elegant way to handle this? Also note that I bind this file on the page before this one also and I needed to remove the binding on that page also in order to avoid the error.
private async void btnTakePic_Click(object sender, RoutedEventArgs e)
{
await CameraCapture();
}
private async Task CameraCapture()
{
CameraCaptureUI camUI = new CameraCaptureUI();
camUI.PhotoSettings.AllowCropping = true;
camUI.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.MediumXga;
camUI.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
Windows.Storage.StorageFile imageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (imageFile != null)
{
IRandomAccessStream stream = await imageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapCamera = new BitmapImage();
bitmapCamera.SetSource(stream);
// Use unique id for image name since name could change
string filename = student.StudentID + "Photo.jpg";
await imageFile.MoveAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);
student.UriPhoto = new Uri(string.Format("ms-appdata:///local/{0}", filename), UriKind.Absolute);
}
}
Here is the binding portion just for fun:
<Image x:Name="imgStudent" Grid.Row="0" Width="400" Height="300" Margin="15" Grid.ColumnSpan="2">
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="{Binding UriPhoto}" />
</Image.Source>
</Image>
Upvotes: 2
Views: 542
Reputation: 568
Ok, well after several hours of research, I've concluded that it is near impossible to bind to a Uri
, and the alternative is to bind a BitmapImage
. I couldn't find the exact reason, but it has something to do with the fact that using a Uri
leaves the BitmapImage
open and binding quickly breaks this paradigm. The solution is to bind the BitmapImage
and set the BitmapImage
to a stream, which seems to support binding quite well.
I liked the idea of the Uri
since its easily seriliazable, while the BitmapImage
is more difficult and takes up significantly more space (since you are serializing the picture data as opposed to a link). The solution that I decided on and that works is to serialize the Uri
, and use the OnDeserialized
attribute to create the BitmapImage
on startup. I then needed a method/event to reset the BitmapImage
whenever the Uri
changed.
Here's the final code to recap:
private async Task CameraCapture()
{
CameraCaptureUI camUI = new CameraCaptureUI();
camUI.PhotoSettings.AllowCropping = true;
camUI.PhotoSettings.MaxResolution = CameraCaptureUIMaxPhotoResolution.MediumXga;
camUI.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
Windows.Storage.StorageFile imageFile = await camUI.CaptureFileAsync(CameraCaptureUIMode.Photo);
if (imageFile != null)
{
// Use unique id for image name since name could change
string filename = student.StudentID + "Photo.jpg";
// Move photo to Local Storate and overwrite existing file
await imageFile.MoveAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);
// Open file stream of photo
IRandomAccessStream stream = await imageFile.OpenAsync(FileAccessMode.Read);
BitmapImage bitmapCamera = new BitmapImage();
bitmapCamera.SetSource(stream);
student.BitmapPhoto = bitmapCamera // BitmapImage
// Save Uri to photo since we can serialize this and re-create BitmapPhoto on startup/deserialization
student.UriPhoto = new Uri(string.Format("ms-appdata:///local/{0}", filename), UriKind.Absolute);
}
}
And the new XAML binding to the student BitmapImage
<Image x:Name="imgStudent" Source="{Binding BitmapPhoto}" Grid.Row="0" Width="400" Height="300" Margin="15" Grid.ColumnSpan="2"/>
Upvotes: 2