2

I am doing image Read/Copy operations in WPF application. Please look at following piece of code:

try
{
  if (sourceDir != "")
    File.Copy(sourceDir, Path.Combine(backupDir, ecode + ".jpg"), true);
}
catch (Exception exx)
{
    MessageBox.Show(exx.ToString());
}

Now let explain problem with a scenario:
First time when this code executes the sourceDir and Path.Combine(backupDir, ecode + ".jpg") values are:
sourceDir="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"
Path.Combine(backupDir, ecode + ".jpg")="D:\IEPL-archives-Do not Modify\DATA\654.jpg"
It works fine for the first time and file is being copied to its destination folder.

But for the second time when this code executes with following values:
sourceDir="C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg"
Path.Combine(backupDir, ecode + ".jpg")="D:\IEPL-archives-Do not Modify\DATA\654.jpg"
It throws following exception:

enter image description here

I am also displaying same image in UI, that is causing this exception. Here is the code which displays the image in UI:

image1.Source = new BitmapImage(new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute));
private string GetPicture(string _eid)
    {
        string picname = "";
        if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpg"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpg";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpeg"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".jpeg";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".png"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".png";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".gif"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".gif";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPEG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".JPEG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".PNG"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".PNG";
        else if (File.Exists(@"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".GIF"))
            picname = @"D:\IEPL-archives-Do not Modify\DATA\" + _eid + ".GIF";
        else
            picname = @"Images\defaultPicture.jpg";
        return picname;
    }

Please suggest how can i modify the code so that this conflict will not arise? Thanks

Azeem
  • 2,904
  • 18
  • 54
  • 89
  • Is the image (D:\IEPL-archives-Do not Modify\DATA\654.jpg) being shown in the UI? – ekholm Jun 27 '12 at 13:49
  • @ekholm yes this image is shown in UI at the same time. – Azeem Jun 27 '12 at 13:52
  • Both `Path.Combine(backupDir, ecode + ".jpg")` have the **same** target image location. Is this intended? If not, that might already the reason for your exception... – Jens H Jun 27 '12 at 13:54
  • @JensH I got your point. I have to display the picture on UI as well and i am doing it with this code: `image1.Source = new BitmapImage(new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute));` – Azeem Jun 27 '12 at 13:56

4 Answers4

4

You should load the image into memory using BitmapCacheOption.OnLoad. That will release the lock on the file.

BitmapImage bi = new BitmapImage();
bi.BeginInit();

bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(GetPicture(txtBarcode.Text), UriKind.RelativeOrAbsolute);

// End initialization.
bi.EndInit();
image1.Source = bi;
ekholm
  • 2,543
  • 18
  • 18
  • after updating with this code now there is no exception but image file is not being updated/replaced with the new one!! – Azeem Jun 27 '12 at 14:10
  • Can't see why image file is not replaced if you call File.Copy with a new source path, and no exception is raised. Are you sure about that? – ekholm Jun 27 '12 at 14:24
  • If you mean that the image in UI doesn't update, that's expected. You would need to reload it. – ekholm Jun 27 '12 at 14:24
  • @ekholm my mistake!! this code works perfectly. Actually the windows was not updating the images thumbnails in destination folder that's why I was assuming that images were not updated. But when i open an image then it was the required image inside (but thumbnail was different). Can you tell me why this is happening? – Azeem Jun 27 '12 at 14:27
  • The thumbnails of the images in a folder are cached and mapped to filenames, and obviously not automatically reloaded on this kind of file access. Glad you got it to work anyway! – ekholm Jun 27 '12 at 14:32
  • @ekholm Can I also refresh/reload the updated files thumbnails through code? – Azeem Jun 27 '12 at 15:48
1

According to the previous comments it might be that the file handle stays open after displaying it in the UI. So I guess that after you copy it for the first time and then display it, the handle possibly never gets closed.

And, as you keep overwiting the same target image name, the code then throws the mentioned exception.

This would be exactly the case if you are using something Image.FromFile() methood, for example. This indeed keeps the handles open until the end of the application...

[EDIT after you updated the question]

You need to change the caching options to:

From the MSDN documentation:

Set the CacheOption to BitmapCacheOption.OnLoad if you wish to close a stream used to create the BitmapImage. The default OnDemand cache option retains access to the stream until the image is needed, and cleanup is handled by the garbage collector.

(Code copied from documentation.)

// Define a BitmapImage.
Image myImage = new Image();
BitmapImage bi = new BitmapImage();

// Begin initialization.
bi.BeginInit();

// Set properties.
bi.CacheOption = BitmapCacheOption.OnLoad; // <-- This is the important one
bi.CreateOptions = BitmapCreateOptions.DelayCreation;
bi.DecodePixelHeight = 125;
bi.DecodePixelWidth = 125;
bi.Rotation = Rotation.Rotate90;
MessageBox.Show(bi.IsDownloading.ToString());
bi.UriSource = new Uri("smiley.png", UriKind.Relative);

// End initialization.
bi.EndInit();
myImage.Source = bi;
myImage.Stretch = Stretch.None;
myImage.Margin = new Thickness(5);

And after loading the image, do not forget to throw the NotifyPropertyChanged event the WPF recognizes the change... ;-)

Jens H
  • 4,590
  • 2
  • 25
  • 35
0

I think that the first step is to determine which process has locked your file. To do that, I recommend using Handle from Sysinternals. As soon as the exception raises, use the app to check it out.

If the delay suggested by the other answer is enough to copy the file, it may be that you can't really use the tool to check that. In this case, you need an automated solution to determine who is locking the file. You can use WMI to do that.

Now, my guess is that your process is locking the file, which would mean some sort of bug or unintended behavior from File.Copy.

EDIT: Ok, now we know you are the one opening the file...

Bruno Brant
  • 8,226
  • 7
  • 45
  • 90
0

You can load the file into memory, and then can create BitmapImage from in memory data.

    BitmapImage GetImage( String filepath)
    {
        byte[] rawImageBytes = File.ReadAllBytes(filepath);
        BitmapImage imageSource = null;

        try
        {
            using ( MemoryStream stream = new MemoryStream( rawImageBytes  ) )
            {
                stream.Seek( 0, SeekOrigin.Begin );
                BitmapImage b = new BitmapImage();
                b.SetSource( stream );
                imageSource = b;
            }
        }
        catch ( System.Exception ex )
        {
        }

        return imageSource;
    }

byte array to BitmapImage code is taken from this SO question

Community
  • 1
  • 1
Tilak
  • 30,108
  • 19
  • 83
  • 131