InvokeMember(“click”) 在线程内的 webBrowser 控件中不起作用

发布于 2024-10-08 19:16:13 字数 2142 浏览 0 评论 0原文

我正在尝试创建一个多线程应用程序,该应用程序创建 Web 浏览器并对每个浏览器执行特定的操作。当我从主线程尝试我的代码时,它工作得很好,但是,当我将代码更改为从线程运行时,代码运行良好,直到调用 InvokeMember("click") 且没有任何反应。 InvokeMember() 未执行,并且按钮单击未发生。这是我的代码:

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", "[email protected]");
    wb.Document.GetElementById("F4").SetAttribute("Value", "[email protected]");
    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;
        }
    }
}

请注意,当从主线程调用 Work() 时,它运行得非常正确。问题在于从另一个线程调用它。

提前致谢。

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", "[email protected]");
    wb.Document.GetElementById("F4").SetAttribute("Value", "[email protected]");
    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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

万人眼中万个我 2024-10-15 19:16:13

您违反了 STA 线程的硬性要求,它必须泵送消息循环。您通过调用 Application.DoEvents() 修补了 Navigate 方法的麻烦。这会推动消息循环。但您不是为 InvokeClick 执行此操作。

检查此答案以获取解决方案。将代码放入 DocumentCompleted 事件中。我认为没有明显的方法来决定何时停止线程,您可能必须使用计时器来轮询单击的某种副作用。

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.

妄断弥空 2024-10-15 19:16:13

JFYI,您可以使用 LINQ 执行以下操作:

var element = elements
    .OfType<HtmlElement>()
    .Select(element => element.GetAttribute("value"))
    .FirstOrDefault(value=> String.Equals(value, "Sign Up"));
if (element != null)
    element.InvokeMember("click");

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");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文