foreach problems

I'm using a foreach loop to run through a folder of images.  I have the code set to display the images so that I know something is happening, but only one of the images seems to be displaying. Here is the code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace NewImageReader
{
   
       
    public partial class JpegReader : Form
    {

        private void LUBits()
        {

            foreach (string img in Directory.GetFiles(@"C:\Users\Giles Kingsley\Desktop\ProjectImages"))
            {
                Bitmap bmp = new Bitmap(img) as Bitmap;

                //Display the image
                imageHolder.Image = bmp;
                System.Threading.Thread.Sleep(1);

                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                System.Drawing.Imaging.BitmapData bmpData =
                    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                    bmp.PixelFormat);

                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;
                // Declare an array to hold the bytes of the bitmap.
                int bytes = bmpData.Stride * bmp.Height;
                byte[] rgbValues = new byte[bytes];

                // Copy the RGB values into the array.
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                // unlock the bitmap buffer
                bmp.UnlockBits(bmpData);

            }
        }
        private void button1_Click_1(object sender, EventArgs e)
        {
            LUBits();
        }
        public JpegReader()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            LUBits();
        }
    }
}
antarctican69Asked:
Who is Participating?
 
OklahomaDaveCommented:
Okay, my friend, I won't promise this is the best, most elegant way to accomplish your objective, but it works, and perhaps you can tailor it to your needs. It fires up a background thread and a GUI update delegate to refresh the image control after each new image is sent.

I hope this helps.

=David

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;


    public partial class JpegReader : Form
    {
        delegate void ImageUpdaterDelegate(PictureBox imageHost, Bitmap image);

        Thread updaterThread;

        public static void ImageUpdater(PictureBox imageHost, Bitmap image)
        {
            if (imageHost.InvokeRequired)
            {
                imageHost.Invoke(new ImageUpdaterDelegate(ImageUpdater), new object[]{imageHost, image});
            }
            else
            {
                imageHost.Image = image;
                imageHost.Refresh();
            }
        }


        private void LUBits(String img)
        {


                Console.WriteLine(img);
                Bitmap bmp = new Bitmap(img) as Bitmap;

                ImageUpdater(imageHolder, bmp);

                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
                System.Drawing.Imaging.BitmapData bmpData =
                    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                    bmp.PixelFormat);

                // Get the address of the first line.
                IntPtr ptr = bmpData.Scan0;
                // Declare an array to hold the bytes of the bitmap.
                int bytes = bmpData.Stride * bmp.Height;
                byte[] rgbValues = new byte[bytes];

                // Copy the RGB values into the array.
                System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);

                // unlock the bitmap buffer
                bmp.UnlockBits(bmpData);

        }
        public void StartUpdate()
        {
            foreach (string img in Directory.GetFiles(@"your path goes here"))
            {
                LUBits(img);
                Thread.Sleep(1000);
            }
            
        }
        private void button1_Click_1(object sender, EventArgs e)
        {
            updaterThread = new Thread(new ThreadStart(this.StartUpdate));
            updaterThread.Start();
        }
        public JpegReader()
        {
            InitializeComponent();
        }

    }

Open in new window

0
 
mrjoltcolaCommented:
Wrap the code inside the loop with a try / catch to ensure an exception isn't kicking it out.
0
 
OklahomaDaveCommented:
May be a silly question, but is there any chance there's a non-image file in that folder, and the app is just crashing when it tries to process it as an image??
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
antarctican69Author Commented:
there is nothing but images in the folder.  Tried the try/catch wrapper, but no dice.  The program is not going through all the files, that is the problem.  Could it be where I have the display code?
0
 
iHadiCommented:
To debug the problem try the following:

1. Can you modify your code or set a breakpoint to make sure that all the images pathes are returned from the Getfiles() method.

2. If all the files are in the string array, make sure that the images are not drawn over each other. Check if the image that is drawn is the last one in the array.

3. Try using GDI+ methods to draw the images and make sure that all files are in correct format.
0
 
saraganiCommented:
imageHolder.Image = bmp;
I can assume that imageHolder is a picturebox or something like that.
Since you are itterating and setting the same property for each image, only the last image will be shows on your picturebox.
0
 
OklahomaDaveCommented:
Problems with timed GUI updates always make me suspect painting and refresh issues. I suspect that since all the updating is happening in a single event, with a one-second delay as each image is loaded into the control, the form never has a chance to repaint itself with each update, so you only see one of the updates as the form has only refreshed itself one time.

There are a few ways to handle this.  At a minimum, I would call the Refresh method of the control hosting the image (presumably a PictureBox?) after the new image is loaded.bIf a pure call to Refresh doesn't solve the problem, I'd consider spinning up a background thread to fire every second and marshal a call back to the GDI thread to perform the update.  I'll see if I can spin up an example for you in a sec...

-David


0
 
saraganiCommented:
The sleep is 1ms not 1 second.
0
 
antarctican69Author Commented:
Hey thanks for all the ideas, I will have to get back to you on how they worked, as other matters press, but I think that root of the display problem is in the problems you've mentioned.  More work to follow, but thanks again
0
 
OklahomaDaveCommented:
Antarctican69,

You're welcome. Please remember to let those of us who offered help know how this worked out if you're not closing the issue right now...
0
 
käµfm³d 👽Commented:
You're trying to perform long-running logic in the same thread that all of your GUI controls are created on. As OklahomaDave demonstrates, you should spawn a separate thread to perform the long-running logic.

When you you do lengthy logic in a GUI object's event handler, provided it an object created on the main thread, you cause the message pump that processes messages like, "move window", "draw button", etc. to freeze up and not process any messages until the long-running logic completes. You have probably run into "Form not responding..." messages in your title bar from time to time. This is why.

The quick-and-dirty way to handle this is to use Application.DoEvents(). But this is generally seen as an improper way to handle this scenario. As already mentioned, a separate thread overcomes this problem.

In addition to using a custom Thread object, you may consider looking into the ThreadPool or the BackgroundWorker. Both have internal threads to handle lengthy processes, but each handles creation and destruction of threads internally---you just worry about your logic and updating your UI appropriately.
0
 
käµfm³d 👽Commented:
provided it an object created on the main thread
Aahhh typos...   That should read:

    provided it is not an object created on the main thread
0
 
käµfm³d 👽Commented:
P.S.

Calling Refresh(), Update(), or Invalidate() won't work because of the aforementioned message blocking.
0
 
antarctican69Author Commented:
You are da' man.  I have no idea what you did, but the code works for what I want.  I'm really new at this, so it's nice to have some ready-bake code to work off.
0
 
OklahomaDaveCommented:
You're welcome, antarctican! I'm glad it worked out for you!

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.