2014-11-11 11 views
5

Desidero attendere la fine di un timer e quindi tornare da una funzione. Ho provato questo:Come attendere il termine del timer e poi tornare dalla funzione?

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

Ma non ha funzionato e la funzione è tornata prima che il timer finisse davvero. Ecco la funzione completa:

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; 
} 

risposta

5

Penso che quello che in realtà si vuole è aspettare che il browser sia pronto. Se così si può utilizzare un ciclo come questo, e invece di Application.DoEvents() mi consiglia di utilizzare async/await funzione:

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

O meglio è possibile gestire DocumentCompleted caso di browser web.

+0

L'ho fatto funzionare, grazie! ma se chiamo la mia funzione dopo quel ciclo, i contenuti caricati da Ajax non sono disponibili :( – Jack

1

È possibile utilizzare uno Thread anziché uno Timer. Avvia il tuo metodo di attesa in una discussione e aspetta semplicemente che finisca con thread.IsAlive.

Il codice deve essere simile a questo:

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; 
+0

Lo hai testato in una pagina con alcuni contenuti caricati da ajax? la funzione restituisce prima che roba di ajax sia caricata – Jack

1

Invece di usare Await/Async e cambiare la firma del metodo si potrebbe usare CountdownEvent e filettatura.

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; 

}

Il CountdownEvent bloccherà il thread corrente fino a quando il contatore raggiunge 0. Poiché la classe Timer utilizza un ThreadPool per la richiamata, tale evento sarà ancora fuoco e lavorare come normale.

2

Non entrerò nel merito di questo approccio. Ma puoi semplicemente farlo con una bandiera.

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; 
} 

E probabilmente dovresti inserire anche un Thread.Sleep nel ciclo while.

1

Basta inserire qualche_valore in una variabile di livello di classe, quindi fare in modo che il timer generi un evento. Qualsiasi funzione che chiama la tua funzione può (prima della chiamata) iscriversi all'evento e quindi gestirlo.