9

I already had an image inside PictureBox control, and now I want to pass a new one to it.

What happens, is that allpication Disposes (and I catch an exception: "Parameter is not valid").

This is my code:

            using (Image img = Image.FromFile(open.FileName))
            {
                part.Picture = img;
                pictureBox1.InitialImage = null;
                pictureBox1.Image = img;
            }    

So when the code goes out of the method, it goes streight to Displose of this and main form. I catch the exception only on line where Form1 was started. On this one there is no excpetions what so ever. It must be something wrong while pictureBox is painting (inside Paint event), but I am not surbsribed to it.

I really dont have any more clue how to salve this issue. I have even tried to use to clear all resources (by calling garbage collection), but nothing seems to work.


One more thing: "part" is a reference of the List, so when I try to Delete the current image (to replace it with a new one) I got another exception, like:

"The process cannot access the file because it is being used by another process".


Does this has something to do with the 1st exception (when new image is not painted in pictureBox)?

Mitja Bonca
  • 4,268
  • 5
  • 24
  • 30
  • Can you please post the full method that contains the code of the Image you want to pass.. this is a very easy fix but I would like to see the code first so that I don't provide you with an incorrect solution.. – MethodMan Oct 01 '12 at 20:34
  • Should `pictureBox1.Image = img;GC.` be `pictureBox1.Image = img;`? What is `part`? What line is the exception being thrown on? Is there a stack trace with the exception? – Trisped Oct 01 '12 at 20:35

4 Answers4

13

As Reed noted, the Image you are pulling from open.Filename is being disposed once you exit the using() statement. Your picturebox is still referencing this image in memory, so when it is disposed, you lose what was stored in your picturebox too.

What you really need is a unique copy of the image you are pulling.

    using (Image sourceImg = Image.FromFile(open.Filename))
    {
        Image clonedImg = new Bitmap(sourceImg.Width, sourceImg.Height, PixelFormat.Format32bppArgb);
        using (var copy = Graphics.FromImage(clonedImg))
        {
            copy.DrawImage(sourceImg, 0, 0);
        }
        pictureBox1.InitialImage = null;
        pictureBox1.Image = clonedImg;
    }

This way, your file will be unlocked as soon as you exit this block, and you'll keep a unique copy of your image in the picturebox.

MadHenchbot
  • 1,306
  • 2
  • 13
  • 27
  • Here is a good reference for this behavior: http://support.microsoft.com/?id=814675 – MadHenchbot Oct 01 '12 at 22:11
  • 1
    PERFECT! I dont know what I was thinking, a reference only means its a copy of an actual data. So when disposed, its all lost! Thx ones again. – Mitja Bonca Oct 01 '12 at 22:19
5

The problem is that, after this code executes, pictureBox1.Image is referring to an Image which has been disposed.

If you do not wrap the Image creation in a using, it should correct your issue.

Image img = Image.FromFile(open.FileName);
part.Picture = img;
pictureBox1.InitialImage = null;
pictureBox1.Image = img; // You can't dispose of this, or it won't be valid when PictureBox uses it!
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Would it be nice to check if there is an image already in the picture box before changing it. If an image does exist, how about disposing it? – swiftgp Oct 01 '12 at 20:37
  • 1
    @user1556110 That would be good - if it's not also used in `part.Picture` (whatever that is)... Didn't want to do that since its stored elsewhere, too... – Reed Copsey Oct 01 '12 at 20:38
  • :) you are the man, but I still have a question, read my next post. – Mitja Bonca Oct 01 '12 at 20:48
  • @user1556110: There already is an image inside pictureBox. I did "dispose" it, by asigning Image property to null. Is this OK? – Mitja Bonca Oct 01 '12 at 20:50
  • @MitjaBonca Would be better to store a reference to it, assign the new one, then call Dispose() yourself (if you know it's not used elsewhere) – Reed Copsey Oct 01 '12 at 20:52
0

You could also do something like the following create a method that loads the images and then pass it back to the Image Control for example this is what I am using when I want to populate an Image Ctrl

I have a windows form with 3 different Images that I want to load but I am only showing the code for One since I call the same method for all 3 Image Controls

    #region Codes for browsing for a picture
    /// <summary>
    /// this.picStudent the name of the Image Control
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnStudentPic_Click(object sender, EventArgs e)
    {
        Image picture = (Image)BrowseForPicture();
        this.picStudent.Image = picture;
        this.picStudent.SizeMode = PictureBoxSizeMode.StretchImage;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    private Bitmap BrowseForPicture()
    {
       // Bitmap picture = null;

        try
        {
            if (this.fdlgStudentPic.ShowDialog() == DialogResult.OK)
            {
                byte[] imageBytes = File.ReadAllBytes(this.fdlgStudentPic.FileName);
                StudentPic = new Bitmap( this.fdlgStudentPic.FileName);
                StuInfo.StudentPic = imageBytes;
            }
            else
            {
                StudentPic = Properties.Resources.NoPhotoAvailable;
            }
        }
        catch (Exception)
        {
            MessageBox.Show("That was not a picture.", "Browse for picture");
            StudentPic = this.BrowseForPicture();
        }

        return StudentPic;
    }
    #endregion
MethodMan
  • 18,625
  • 6
  • 34
  • 52
0

Yes, this is now working, but strange, I would almost swear I tried this way too. Ok, never mind, just that it works. What is troubling me is something else too, which is in my opinion the same as your code, but its not working, its again trying to Dispose application (with same exception). This is an example code:

using(Image img = Image.FromFile(open.FileName))
{
   part.Picture = img; 
}
pictureBox1.InitialImage = null;
pictureBox1.Image = part.Picture;  //Picture  is a propery in a class

Now I pass an actual image into a generic list, and try to assign new image to pictureBox from it, but, again as I said, exception is thrown (and application is terminated). Why?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Mitja Bonca
  • 4,268
  • 5
  • 24
  • 30
  • 1
    When you use a `Using` block, the instance is disposed immediately after your code exits the block, whether or not it has references some where else. – swiftgp Oct 01 '12 at 20:50
  • But part.Image already has an actual image asigned, doesnt it? So it should work. Or am I wrong? – Mitja Bonca Oct 01 '12 at 20:59
  • 1
    The code "part.Picture = img" only copies the image reference, it does not clone the image. So when img gets disposed at the end of the using{} block, the reference to the image is no longer valid, and part.Picture will contain a null reference. – deegee Jun 21 '13 at 21:06