PictureBox's throws exception when changing Image
Asked Answered
F

0

0

I have a Dictionary with pairs of strings and Bitmaps that corresponds to a ListView control that lists all the image keys, among other info. Also I have a PictureBox that must show the corresponding image of the dictionary when the listview's index changes. Multiselect is set to false. The DateTime is there in order to ensure that only the most recent "selected" image is loaded.

When the index changes, randomly one of this things happens:

  1. The image loads correctly
  2. No change occurs on the Picturebox
  3. A System.ArgumentException is thrown. The exception is always thrown in the same line (see code)

How can I prevent #2 and #3 happening?

Here is the code:

private Dictionary<string, Bitmap> dictionary;
private ReaderWriterLockSlim dictionary_lock;

private DateTime _LAST_PREVIEW_UPDATE;
private DateTime LAST_PREVIEW_UPDATE
{
    get { return _LAST_PREVIEW_UPDATE; }
    set 
    {
        if(value.CompareTo(_LAST_PREVIEW_UPDATE) < 0)
            _LAST_PREVIEW_UPDATE = value; 
    }
}

/* ... */

private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
    if (this.listView1.SelectedItems.Count != 1)
        return;

    DateTime now = DateTime.Now;
    string image_code = this.listView1.SelectedItems[0].SubItems[0].Text;

    Thread t = new Thread(() =>
    {
        Bitmap image = null;
        bool load_properly;

        dictionary_lock.EnterReadLock();
        try
        {
            load_properly = dictionary.TryGetValue(image_code, out image);
        }
        finally
        {
            dictionary_lock.ExitReadLock();
        }

        if (!load_properly)
        {
            /* LOG THE ERROR */
            return;
        }

        this.BeginInvoke((MethodInvoker)delegate
        {
            if (now.CompareTo(LAST_PREVIEW_UPDATE) > 0)
            {
                LAST_PREVIEW_UPDATE = now;
                if (picturebox.Image != null)
                    picturebox.Image.Dispose();
                picturebox.Image = image; // This throws the exception
            }
        });
    });

    lock (picturebox)
    {
        t.Start();
        t.Join(3000);
    }
}

EDIT: Here is the call stack

    System.Drawing.dll!System.Drawing.Image.FrameDimensionsList.get() + 0x258 bytes 
    System.Drawing.dll!System.Drawing.ImageAnimator.CanAnimate(System.Drawing.Image image) + 0x6d bytes 
    System.Drawing.dll!System.Drawing.ImageAnimator.ImageInfo.ImageInfo(System.Drawing.Image image) + 0x26 bytes    
    System.Drawing.dll!System.Drawing.ImageAnimator.Animate(System.Drawing.Image image, System.EventHandler onFrameChangedHandler) + 0x97 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.PictureBox.Animate(bool animate) + 0x65 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.PictureBox.InstallNewImage(System.Drawing.Image value, System.Windows.Forms.PictureBox.ImageInstallationType installationType) + 0xc8 bytes   
>   Application.exe!Application.FrmMain.listView1_SelectedIndexChanged.AnonymousMethod__a() Line 596 + 0x78 bytes   C#

EDIT2: I want to implement the functionality explained before, but this is the better approach I could get. Calling directly from the UI-thread was too slow (evidently) so I tried executing it from another thread. I want the image to represent the last selected item on the list view, but simply summoning threads could (and would) cause a race condition, so I need a mechanism to prevent/discard old selected indexes from changing the image, so only the last selected index decides which image to load.

Thanks for your time!

Flit answered 25/6, 2013 at 23:33 Comment(4)
2) is simply explained with the logic of your code. 3) requires an exact exception message and its stack trace. The thread does nothing useful at all, get rid of it to avoid failure modes.Phantasy
@HansPassant 2) I posted here because I can't see the error =( 3) Added at the end of the post Thanks buddy!Flit
The stack trace shows evidence of an animated GIF image with corrupted file content. Use try/catch around the Image property assignment to catch bad files. Verify that it is repeatable for this specific image file. If it is not then you may well have memory problems, images can gobble up a large amount of unmanaged memory. Your program being "slow" is another hint that this is the root problem. Fix that by just storing the filename in the dictionary instead of the entire image so you only have a single image loaded instead of all of them.Phantasy
@HansPassant Well, I saw the stack but all the image's are tiff, definitely not animated, but I'll try loading the files from File instead of memory and will diagnose with other images.Flit

© 2022 - 2024 — McMap. All rights reserved.