5

I want to wait to a timer finish and then return from a function. I tried this:

while(timer1.Enabled)
{
    Application.DoEvents();
}
return value;

But it didn't work and the function returned before the timer really finished. Here's the full function:

System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
int[] foo()
{

    do_something1();

    int[] some_value;

    timer1.Interval = 1000;
    timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
    {
        if (browser.ReadyState == WebBrowserReadyState.Complete)
        {
            timer1.Stop();
            baa(some_value);
        }
    });
    timer1.Start();

    while (timer1.Enabled)
    {
        Application.DoEvents();
    }

    return some_value;
}
Slippery Pete
  • 3,051
  • 1
  • 13
  • 15
Jack
  • 16,276
  • 55
  • 159
  • 284

5 Answers5

5

I think what you actually want is to wait until the browser is ready. If so you can use a loop like this, and instead of Application.DoEvents() I recommend using async/await feature:

while(browser.ReadyState != WebBrowserReadyState.Complete)
{ 
   // you need to make your method async in order to use await
   await Task.Delay(1000);
}
// do your job

Or better you can handle DocumentCompleted event of WebBrowser.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • I did it work, thanks! but if I call my function after that loop, the contentes loaded by ajax isn't available :( – Jack Nov 15 '14 at 01:51
1

You can use a Thread instead of a Timer. Launch your waiting method in a Thread and simply wait it to finish with thread.IsAlive.

Your code must look like this:

int[] some_value;

int intervalle = 1000;
Thread thread = new Thread(new ThreadStart(delegate()
{
    while (true)
    {
        Thread.Sleep(intervalle);
        if (browser.ReadyState == WebBrowserReadyState.Complete)
        {
            baa(some_value);
            return;
        }
    }                
}));
thread.Start();

while (thread.IsAlive)
{
    Application.DoEvents();
}

return some_value;
Ludovic Feltz
  • 11,416
  • 4
  • 47
  • 63
  • Have you tested it in a page with some contentes loaded by ajax? the function return before that ajax stuff is loaded – Jack Nov 14 '14 at 18:26
1

Instead of using Await/Async and change the method signature you could use CountdownEvent and threading.

using System.Theading;
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();

int[] foo()
{
  int numberOfIterations = interval time * number of intervals; // initialize this to the proper number of times to decrement the counter. If we are decrementing every 1000 ms
  CountdownEvent countDown = new CountdownEvemt(numberOfIterations);
  do_something1();

  int[] some_value;

  timer1.Interval = 1000;
  timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
  {
      if (browser.ReadyState == WebBrowserReadyState.Complete)
      {
          timer1.Stop();
          baa(some_value);
          // since this seems where you want to shut down the method we need to trigger the countdown
          int countLeft = countDown.CurrentCount;
          countDown.Signal(countLeft); 
      } else {
          if(countDown.CurrentCount - 1 == 0) {
              countDown.Reset(); // we don't want to finish yet since we haven't reached the proper end condition so reset the counter
          }
          countDown.Signal(); // will decrement the counter
      }
  });
  timer1.Start();

  countDown.Wait(); // will wait 'til the counter is at 0 before continuing
   return some_value;

}

The CountdownEvent will block the current thread until the counter reaches 0. Since the Timer class uses a ThreadPool for its callback, that event will still fire and work as normal.

Jetti
  • 2,418
  • 1
  • 17
  • 25
1

I will not go into how good or bad this approach is. But you can simply do this with a flag.

System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
int[] foo()
{

    do_something1();

    int[] some_value;

    bool doneWaiting = false;

    timer1.Interval = 1000;
    timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
    {
        if (browser.ReadyState == WebBrowserReadyState.Complete)
        {
            timer1.Stop();
            baa(some_value);
            doneWaiting = true;
        }
    });
    timer1.Start();

    while (!doneWaiting)
    {
        Application.DoEvents();
    }

    return some_value;
}

And you should probably put a Thread.Sleep in the while loop also.

Gregor Stamač
  • 184
  • 1
  • 5
1

Simply put some_value into a class-level variable, then have the timer raise an event. Any function calling your function can (before the call) subscribe to the event and then handle it.