1

I am trying to create a multi-threaded application that creates WebBrowsers and does specific things to each one. When I tried my code from the main thread it worked great, However, When I changed the code to run from a thread, the code runs fine until InvokeMember("click") is called and nothing happens. InvokeMember() isn't executed and the button click doesn't take place. Here is my code:

private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(Work);
    t.SetApartmentState(ApartmentState.STA);
    t.Start();      
}

[STAThread]
void Work()
{
    WebBrowser wb = new WebBrowser();
    wb.ScriptErrorsSuppressed = false;
    wb.Visible = true;
    wb.Navigate("http://website.com");

    while (wb.ReadyState != WebBrowserReadyState.Complete)
    {
        Application.DoEvents();
    }
    //updateText("Loaded");
    wb.Document.GetElementById("F1").SetAttribute("Value", "Test");
    wb.Document.GetElementById("F2").SetAttribute("Value", "Saracostaz");
    wb.Document.GetElementById("F3").SetAttribute("Value", "Tester5123@hotmail.com");
    wb.Document.GetElementById("F4").SetAttribute("Value", "Tester5123@hotmail.com");
    wb.Document.GetElementById("F5").SetAttribute("Value", "limewire");
    wb.Document.GetElementById("F6").SetAttribute("SelectedIndex", "1");
    wb.Document.GetElementById("F7").SetAttribute("SelectedIndex", "2");
    wb.Document.GetElementById("F8").SetAttribute("SelectedIndex", "5");
    wb.Document.GetElementById("F9").SetAttribute("SelectedIndex", "20");
    // updateText("Entered Data");

    HtmlElementCollection elements = wb.Document.Body.All;
    foreach (HtmlElement element in elements)
    {
        string valueAttribute = element.GetAttribute("value");
        if (!string.IsNullOrEmpty(valueAttribute) && valueAttribute == "Sign Up")
        {
            element.InvokeMember("click");
            //MessageBox.show("I am in"); //that messagebox shows normally.
            break;
        }
    }
}

Please note that the Work() runs very correctly when it's called from the main thread. The problem lies in calling it from another thread.

Thanks in advance.

dlock
  • 9,447
  • 9
  • 47
  • 67

2 Answers2

1

You are violating a hard requirement for an STA thread, it must pump a message loop. You patched your way out of trouble with the Navigate method by calling Application.DoEvents(). That pumps the message loop. But you are not doing this for InvokeClick.

Check this answer for the solution. Put the code in the DocumentCompleted event. There is no obvious way I see to decide when to stop the thread, you'd have to poll for some kind of side-effect of the click with a timer perhaps.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

JFYI, you can do next using LINQ:

var element = elements
    .OfType<HtmlElement>()
    .Select(element => element.GetAttribute("value"))
    .FirstOrDefault(value=> String.Equals(value, "Sign Up"));
if (element != null)
    element.InvokeMember("click");
abatishchev
  • 98,240
  • 88
  • 296
  • 433