Access Denied when deleting image file previously used in DataTemplate in WinRT
Asked Answered
M

5

6

I have image (PNG) files used by my GridView as part of its DataTemplate. If I try to delete a specific object row in my GridView, I would delete the related image file for that row as well. The images are different for every item on the list.

I'm using this code to delete the image file

StorageFile _file = await DataStore.GetFileAsync(filename);
await _file.DeleteAsync(StorageDeleteOption.Default);

The image file is rendered on the GridView under the GridView's DataTemplate. So in each object model in my List, I have a public property there that returns an ImageSource for my DataTemplate.

I'm calling my delete procedure right after i deleted the object row from the List and after the GridView has been refreshed of the new List items.

Even though the List does not contain the object (consuming the image) anymore, the app throws the Access is Denied exception if i try to delete the file. While the app is running, if i try to delete that particular file manually (through file explorer), it won't allow me too.

I tried clearing all unused objects in my app, even setting the GridView's ItemSource to null and the List to null before I delete the image. Still the exception persist.

Thanks in advance.

Misapprehension answered 5/12, 2012 at 7:44 Comment(0)
C
2

One method you can try is to load the image into a memory steam, then create a BitmapImage object from that stream, you can then set the source of your Image control to that bitmap image.

Since you are not using the actual image file as the source of the image, you can easily delete it anytime :)

Canice answered 16/1, 2013 at 5:57 Comment(0)
N
2

Though this is an old question, I have encountered the problem recently in a UWP app and actually managed to find a solution. But first some background information about the problem:

When you create a BitmapImage with a URI, the created URI object holds a reference to the file in your local storage and keeps it open, i.e. non-writable. This btw is only true when the Bitmap is just big enough to fit into the Image entirely, typically small or medium sized Bitmaps. If the Bitmap happens to be big enough, WinRT automatically uses a downsampled version when it is displayed in an Image. In this case the URI does NOT hold a reference to the original file.

Now to the actual solution:

Setting Image.Source to null doesn't do the trick here, as the URI is still alive (until the next GC cycle at least). What DID work for me, was casting the Source to the BitmapImage it originally was and settings the UriSource to null.

var bitmapImage = image.Source as BitmapImage;
if (bitmapImage != null)
  bitmapImage.UriSource = null;

And yes, this IS stupid.

Negrito answered 1/2, 2016 at 18:23 Comment(0)
S
2

Mark already mentioned part of this but there is no need to make it that complicated. Simply, wherever you expect that you need to delete the bitmap while the system is holding it, use a converter like this:

public class SafeImageFileConverter : IValueConverter {
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
    string path = (string)value;
    var stream = new MemoryStream(File.ReadAllBytes(path));
    return ImageSource.FromStream(() => stream);
  }
}

In practice, you might want to check whether the path exists or return an error.png or similar if it doesn't. Also, don't be tempted to use using with the stream, the system will need the stream so you shouldn't dispose it early.

Straightout answered 1/7, 2018 at 15:49 Comment(0)
T
0

The trick is to use a Uri object to load the image (instead of a string filename) and then to use the EXACT same Uri instance to delete the file (after removing the image from the UI, of course). Here is an example:

//Save the Uri as a member variable so you can get to it later
private Uri uri;

//Create the Uri
uri = new Uri(OriginalImageFilename, UriKind.Absolute);

//Load the image
BitmapImage bitmapImage = new BitmapImage(uri);
//This can also be done by binding a Image control's source property to the uri.

//Delete the image (remember to use the same Uri instance)
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(uri);
await file.DeleteAsync();
Threequarter answered 30/12, 2012 at 19:50 Comment(1)
Thanks @kinect_dev, but i'm still getting the error when i tried your suggestion.Misapprehension
M
0

As a work-around, i just deleted the unused images during app launch so that no processes are using it. Thanks.

Misapprehension answered 16/1, 2013 at 5:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.