locked
Access Denied - Saving picture RRS feed

  • Question

  • I have a list of pictures that I allow the user to replace by taking another picture.

    When the user takes another picture, I replace the original picture with the same file name.

    I am getting "Access is Denied" when I execute this line of code:

    var result = await file.CopyAsync(storageFolder, fileName, NameCollisionOption.ReplaceExisting);

    Now I know what is going on, the file is open so the app has it locked and I am trying to replace it.

    I need to be able to "close" an image file so that it can be replaced.

    Can someone suggest a different approach to solving this problem?

     

    Thanks, Terrence


    • Edited by Terrence_ Saturday, June 23, 2012 6:47 PM
    Saturday, June 23, 2012 6:17 PM

Answers

  • hey terrence, in my example I left a note about putting the _Image variable to be a BitmapImage or a WriteableBitmap. You woundnt then need to deal with the dependencies.


    Can Bilgin
    Blog CompuSight


    • Edited by Can Bilgin Sunday, June 24, 2012 8:54 PM
    • Proposed as answer by Jesse Jiang Tuesday, June 26, 2012 5:19 AM
    • Marked as answer by Terrence_ Tuesday, June 26, 2012 9:35 PM
    Sunday, June 24, 2012 7:33 PM

All replies

  • It will be helpful if you provide more information on how exactly your image was open.
    Saturday, June 23, 2012 7:27 PM
  • In general, files are accessed by opening a so called FileStream. This applies to reading, as well as writing operations. Only one FileStream can access a file at a time, so if there's already a FileStream open for a file, this file can't be accessed by another FileStream.

    FileStreams have to be closed/disposed to release a file. In WinRT the method is called Dispose().

    You should check if there's a stream accessing the file. Sometimes you forget to dispose a stream, which takes resources and blocks the file as long as your application is running. Always Dispose Stream objects!

    (Disclaimer: In Windows.Storage.Streams there's no FileStream class, but still: Writing Streams may never have companions.)

    ~theCake


    Life is unsure - always eat the dessert first!

    Saturday, June 23, 2012 7:56 PM
  • The Image files are bound in XAML like so:

    <Image Source="{Binding Image}" Stretch="UniformToFill"/>
    

    The Page's datacontext is my ViewModel.  Here is the image property:

    private ImageSource _Image = null;
    public ImageSource Image
    {
        get
        {
            if (this._Image == null && this._ImagePath != null)
            {
                    this._Image = new BitmapImage(new Uri(Item._baseUri, this._ImagePath));
            }
            return this._Image;
        }
    
        set
        {
            this._ImagePath = null;
            this.SetProperty(ref this._Image, value);
        }
    }
    


    Thanks, Terrence

    Saturday, June 23, 2012 9:03 PM
  • Andrie, I replied to my post about how the image was opened, see below.


    Thanks, Terrence

    Sunday, June 24, 2012 3:41 AM
  • Cake, I am letting windows open the file through binding to my ImageSource, see the code below.

    Thanks, Terrence

    Sunday, June 24, 2012 3:42 AM
  • Good, but have you select a new image before trying to release the old one? I.e. do you assign Image with something new?
    Sunday, June 24, 2012 9:56 AM
  • Hey maybe you don't need to use the image-path to create the image. You can use a clone of the FileStream. BitmapImage.SetSource(IRandomAccessStream) can help doing this. This way you wont be putting a lock on the original file. It is costly but if you really not want to work on the original file:

            private async void SetImage(string path)
            {
                var accessStream = await StorageFile.GetFileFromPathAsync(path);
    
                var randomAccessStream = new InMemoryRandomAccessStream();
    
                await RandomAccessStream.CopyAndCloseAsync(randomAccessStream.GetInputStreamAt(0), randomAccessStream);
                
                // Given that _Image is of type BitmapImage or WriteableBitmap
                this._Image.SetSource(randomAccessStream);
            }

    Or another option is to use a WriteableBitmap as the image. So you can easily change the buffered stream for the image.


    Can Bilgin
    Blog CompuSight


    • Edited by Can Bilgin Sunday, June 24, 2012 12:59 PM added code
    Sunday, June 24, 2012 12:35 PM
  • Yes, I am allowing the user to take a picture and I want to replace the old one with the new one.  Here is what currently happens when I try and save the file.  The filename is the "same" as the old one so we get the conflict.

    StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
    
    var ui = new CameraCaptureUI();
    ui.PhotoSettings.CroppedAspectRatio = new Size(4, 3);
    StorageFile file = await ui.CaptureFileAsync(CameraCaptureUIMode.Photo);
    
    if (file != null)
    {
        string fileName;
        if (!string.IsNullOrEmpty(this.VM.SelectedItem.ShortDescription))
            fileName = this.VM.SelectedItem.ShortDescription + ".jpg";
        else
            fileName = "PictureFirst_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".jpg";
    
        //copy to local storage  location.
        var result = await file.CopyAsync(storageFolder, fileName, NameCollisionOption.ReplaceExisting);
        //show picture on screen.
        var stream = await file.OpenAsync(FileAccessMode.Read);
        var bitmap = new BitmapImage();
        bitmap.SetSource(stream);
        Photo.Source = bitmap;
    
        try
        {
            //var sampleFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(this.BaseUri, @"assets\VolumeDetails.xml"));
            this.VM.SelectedItem.SetImage(fileName);
            this.PictureTaken = true;
        }
        catch (Exception ex)
        {
        }
    }
    


    Thanks, Terrence

    Sunday, June 24, 2012 1:18 PM
  • Can, now that is an interesting approach.  I will study it.


    Thanks, Terrence

    Ok, I am trying this approach and I can't figure it out.  I can't seem to get the dependency property.

    var accessStream = await StorageFile.GetFileFromPathAsync(path);
    var randomAccessStream = new InMemoryRandomAccessStream();
    await RandomAccessStream.CopyAndCloseAsync(randomAccessStream.GetInputStreamAt(0), randomAccessStream);
    // Given that _Image is of type BitmapImage or WriteableBitmap
    this._Image.SetValue(XAML.DependencyProperty DP, randomAccessStream);

    So I need some help with the XAML.DependencyProperty.

    • Edited by Terrence_ Sunday, June 24, 2012 7:25 PM
    Sunday, June 24, 2012 1:18 PM
  • Well I changed my code to set the property right before the copy and I am still getting the same error.

     //copy to local storage  location.

    App.VM.SelectedItem.SetImage(filename);
    var result = await file.CopyAsync(storageFolder, fileName, NameCollisionOption.ReplaceExisting);


    Thanks, Terrence

    Sunday, June 24, 2012 7:00 PM
  • hey terrence, in my example I left a note about putting the _Image variable to be a BitmapImage or a WriteableBitmap. You woundnt then need to deal with the dependencies.


    Can Bilgin
    Blog CompuSight


    • Edited by Can Bilgin Sunday, June 24, 2012 8:54 PM
    • Proposed as answer by Jesse Jiang Tuesday, June 26, 2012 5:19 AM
    • Marked as answer by Terrence_ Tuesday, June 26, 2012 9:35 PM
    Sunday, June 24, 2012 7:33 PM