How do a I efficiently manage a quasi 'task' running in the main thread
<p>I'm developing a small internal-use utility to monitor the uptime and responsiveness of several websites. We have very specialist requirements and criteria to test, hence developing a small application for this.</p>

<p>I have to use the WebBrowser Control to load the website as it has decencies on JavaScript and plug ins which are required. (The test has to be as real world as possible) As a result, my testing has to be run in the GUI thread, currently within the "DocumentCompleted" event.</p>

<p>Additionally, the website I'm testing is AJAX heavy, so I have to implement waiting periods within my logic to ensure that the DOM is loaded as I expect. For example, I check that the  tags are present on the logon the page using a while loop.</p>

<p>My proof of concept works as expected and I'm very happy with the results. However, I'm struggling how to make this more 'task orientated'. For example, I need to implement a timeout period and the ability for the user to cancel what's going on. E.g, the logon page may have failed and so will never show the correct inputs.</p>

<p>At the moment, the only way I can see is to implement logic at every single step to check for a <code>UserCancel</code> variable or check the stopwatch. </p>

<p>I fear I've made a fundamentally bad choice in the architecture of my application, so I'm looking for advice on how to implement the above and improve the code.</p>

<hr>

<pre><code>private void TestSite(string url){

webBrowser.Naviate(url);
stopwatch.Start();

}

private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {

if(stopwatch.Elapsed.Seconds &gt; timeOutValue || userCancel){
//Task timed out, or user has cancelled
return;
}

//Switch to the relevant application logic
//siteStatus is defined by where I expect the website to be at any particular time. 
switch(siteStatus)
{

     case siteStatus.LogonPage:
     if(DocumentTitle != ExpectedDocumentTitle){

     //Page is unexpected. Handle this and return

     }


     //Title is correct, wait until website has built the DOM
     while(stopwatch.Elapsed.Seconds &lt; timeOutValue || !userCancel || webBrowser1.Document.GetElementsByTagName("input").Count() &lt; 2){

     //Carry on
     Application.DoEvents();

     } 

     if(stopwatch.Elapsed.Seconds &gt; timeOutValue){ return; }
     if(userCancel){ return; } 

     //Business logic goes here. Reports on time taken, ensures correct elements are on the page

     break;

     case siteStatus.Menu:

     //Essentially as above with different logic and tests

     break;

    //etc etc

}
</code></pre>
