0

I am attempting to invoke a method as many times as possible given its within 1 second, so I decided to use a timer to help perform this, but when the timer runs the tick event handler (after 1 seconds) the method is still invoked - I have started it of as follows:

public partial class Form1 : Form
    {
        public static Timer prntScreenTimer = new Timer();

        public Form1()
        {
            InitializeComponent();

            startCapture();
        }

        private static void startCapture()
        {
            prntScreenTimer.Tick += new EventHandler(prntScreenTimer_Tick);
            prntScreenTimer.Start();
            prntScreenTimer.Interval = 1000;
            while (prntScreenTimer.Enabled)
            {
                captureScreen();
            }

        }

        private static void prntScreenTimer_Tick(object sender, EventArgs e)
        {
            prntScreenTimer.Stop();
        }

        private static void captureScreen()
        {
            int ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
            int ScreenHeight = Screen.PrimaryScreen.Bounds.Height;
            Graphics g;
            Bitmap b = new Bitmap(ScreenWidth, ScreenHeight);
            g = Graphics.FromImage(b);
            g.CopyFromScreen(Point.Empty, Point.Empty, Screen.PrimaryScreen.Bounds.Size);

            // Draw bitmap to screen
            // pictureBox1.Image = b;

            // Output bitmap to file
            Random random = new Random();
            int randomNumber = random.Next(0, 10000);
            b.Save("printScrn-" + randomNumber, System.Drawing.Imaging.ImageFormat.Bmp);
        }

    }
}
James Teare
  • 372
  • 1
  • 12
  • 23
  • Is your requirement to use the timer or just to invoke the method? If the latter, why don't you just create a basic loop with 'check if the timespan is less than 1 second' as a loop conditon? – Wiktor Zychla May 26 '12 at 18:20

3 Answers3

3

I believe the problem is that you are blocking the main thread in startcapture. The forms Timer needs messages to be processed in order to run. Change the loop to this:

    while (prntScreenTimer.Enabled)
    {
        captureScreen();
        Application.DoEvents();
    }

Since you don't need access to the UI thread from your method this would be better since it won't block the UI:

private void startCapture()
{
    Thread captureThread = new Thread(captureThreadMethod);
    captureThread.Start();
}

private void captureThreadMethod()
{
   Stopwatch stopwatch = Stopwatch.StartNew();
   while(stopwatch.Elapsed < TimeSpan.FromSeconds(1))
   {
       captureScreen();
   }        
}
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
  • DoEvents can make the application work but I would recomment to read these links before using it http://www.codinghorror.com/blog/2004/12/is-doevents-evil.html http://stackoverflow.com/questions/5181777/use-of-application-doevents This a good place to start to play with threading. – L.B May 26 '12 at 18:37
  • @L.B I totally agree. DoEvents is band-aid at best. – Mike Zboray May 26 '12 at 18:43
2

Your code looks correct to me, so I can’t identify the cause of your issue. However, you don’t really need a Timer for what you’re doing; a simple Stopwatch checked within a while loop may suffice:

Stopwatch sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 1000)
    captureScreen();
Douglas
  • 53,759
  • 13
  • 140
  • 188
0

How many times the method is invoked? How did you count this (it cannot be told from the code you pasted).
Whatever the case is, you must remember the elapsed event runs on a separate thread, and therefore such race conditions are possible (your method running once or even more after you stpped the timer). There are of course ways to prevent such race conditions. A somewhat complicated sample to this exists here, on the msdn

YavgenyP
  • 2,113
  • 14
  • 11