Cannot delete file when used in DataContext

2020-02-01 14:11发布

问题:

My application shows images on screen (images based upon files on the local computer) and users can delete them if needed.

Every time I try to delete a file it results in the following error message:

"The process cannot access the file 'C:\\Users\\Dave\\Desktop\\Duplicate\\Swim.JPG' because it is being used by another process."

I understand the error message.

I have a UserControl which accepts a file path (via a parameter in the constructor) and then binds it to it's (UserControl) DataContext.

As part of debugging this issue I have found the issue is due to setting the DataContext within the UserControl. If I remove this.DataContext = this; from within my UserControl then I can delete the file.

So, my TestUnit looks like

        Ui.UserControls.ImageControl ic = new ImageControl(
           @"C:\Users\Dave\Desktop\Duplicate\Swim.JPG");

        try
        {
            File.Delete(@"C:\Users\Dave\Desktop\Duplicate\Swim.JPG");
        }
        catch (Exception ex)
        {
            Assert.Fail(ex.Message);
        }

The UserControl CodeBehind

    public ImageControl(string path)
    {
        this.FilePath = path;
        this.DataContext = this; // removing this line allows me to delete the file!
        InitializeComponent();
    }

    #region Properties

    private string _filePath;
    public string FilePath
    {
        get { return _filePath; }
        set
        {
            _filePath = value;
            OnPropertyChanged("FilePath");
        }
    }

If it matters, my UserControl XAML is using the 'Image' control, bound to 'FilePath'

I have tried making the UserControl null before deleting, this did not help.

I have tried adding the IDisposible Interface to my UserControl and within the Dispose() method setting this.DataContext = null; but this did not help.

What am I doing wrong? How can I delete this file (or more accurately, make it unused).

回答1:

The problem is not the DataContext, but simply the way WPF loads images from files.

When you bind the Source property of an Image control to a string that contains a file path, WPF internally creates a new BitmapFrame object from the path basically like this:

string path = ...
var bitmapImage = BitmapFrame.Create(new Uri(path));

Unfortunately this keeps the Image file opened by WPF, so that you can't delete it.

To get around this you have to change the type of your image property to ImageSource (or a derived type) and load the image manually like shown below.

public ImageSource ImageSource { get; set; } // omitted OnPropertyChanged for brevity

private ImageSource LoadImage(string path)
{
    var bitmapImage = new BitmapImage();

    using (var stream = new FileStream(path, FileMode.Open))
    {
        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.StreamSource = stream;
        bitmapImage.EndInit();
        bitmapImage.Freeze(); // optional
    }

    return bitmapImage;
}

...
ImageSource = LoadImage(@"C:\Users\Dave\Desktop\Duplicate\Swim.JPG");