从线程访问和更改winform webbrowser

时间:2012-01-09 11:28:59

标签: c# windows winforms multithreading

我正在使用Windows应用程序,其中我有一个tabControl,用户可以在其中打开多个标签,就像IE一样。现在我必须访问选定的选项卡,然后必须对打开的文档执行一些操作。

我可以访问它,但在访问所选标签并执行操作后

当我使用另一个线程执行此任务时,

应用程序变为挂起。

请建议我该怎么做。

我正在使用.net 4.0。 C#

参见下面的代码,此代码在按钮上单击

   TextToSpeechThread = new Thread(new ThreadStart(ReadWebDocument));
        TextToSpeechThread.Name = ApplicationManager.GlobalThreadNaming.TextToSpeech.ToString();
        TextToSpeechThread.SetApartmentState(ApartmentState.STA);
        TextToSpeechThread.Start();

这是调用操作的线程方法

 browserTabControl.Invoke(new MethodInvoker(delegate
        {

            browserTabControl.SelectedTab.Controls[0].Invoke(new MethodInvoker(delegate
            {
                WebBrowser _browser = (WebBrowser)(browserTabControl.SelectedTab.Controls[0]);

                my_Voice.Speak(_browser.DocumentTitle.ToString(), my_Spflag);

                foreach (var link in _browser.Document.All)
                {
                    HtmlElement elem = (HtmlElement)(link);
                    Thread tempThread = new Thread(new ParameterizedThreadStart(HighlightingWebDocument));
                    tempThread.Start(elem);

                    if (elem.TagName == "A")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }
                    }
                    if (elem.TagName == "DIV")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }
                        //my_Voice.Speak(elem.TagName.ToString(), my_Spflag);
                    }
                    if (elem.TagName == "IFRAME")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }
                    }
                    if (elem.TagName == "SPAN")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }
                    }
                    if (elem.TagName == "LINK")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }
                    }
                    if (elem.TagName == "INPUT")
                    {
                        if (elem.InnerText != null)
                        {
                            if (elem.InnerText.ToString() != "")
                            {
                                my_Voice.Speak(elem.InnerText.ToString(), my_Spflag);
                            }
                        }

                    }
                    Thread.Sleep(150);
                }
            }));


        }));

现在请提供一些有用的链接......

这是你们提出的另一种方法..

声明代表

delegate void HighlightBrowsercontent(HtmlElement elem);
    HighlightBrowsercontent highLightBrowsercontent = null;

表单加载

  public Form1()
    {
        InitializeComponent();

        // initialise the delegate to point to an implemntation

        highLightBrowsercontent = new HighlightBrowsercontent(OnHighLightContent);

    }

点击按钮,我想要读出内容,并想要突出显示链接。

  private void button1_Click(object sender, EventArgs e)
    {
        HtmlElementCollection links = webBrowser1.Document.Links;

        this.backgroundWorker2.RunWorkerAsync(links);
    }

最后这是我想要执行的过程。

 private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        IAsyncResult res = BeginInvoke(myEnableCancel, new object[] { true });
        ReadDocumetnAsync((HtmlElementCollection)(e.Argument));
        BeginInvoke(myEnableCancel, new object[] { false });
    }

    void ReadDocumetnAsync(HtmlElementCollection elemCollection)
    {
        foreach (var elem in elemCollection)
        {
            HtmlElement elem1 = (HtmlElement)(elem);

            SpeechLib.SpVoice myVoice = new SpeechLib.SpVoice(); ;
            if (elem1.InnerText != null)
            {
                BeginInvoke(highLightBrowsercontent, elem);
                myVoice.Speak(elem1.InnerText);
                System.Threading.Thread.Sleep(450);

                IAsyncResult ar = BeginInvoke(highLightBrowsercontent, elem);// Update the screen
                // Wait until the folder has been created before proceeding with the content of the folde
                while (!ar.IsCompleted)
                {
                    Application.DoEvents();
                    ar.AsyncWaitHandle.WaitOne(-1, false);
                }


            }

        }

    }
 public void OnHighLightContent(HtmlElement element)
    {
        HtmlDocument doc2 = webBrowser1.Document as HtmlDocument;
        toolStripStatusLabel2.Text = element.OuterHtml;
        element.Focus();
        element.ScrollIntoView(false);
        StringBuilder html = new StringBuilder(doc2.Body.OuterHtml);
        String substitution = "<span style='background-color: rgb(255, 255, 0);'>" + element.OuterHtml + "</span>";
        html.Replace(element.OuterHtml, substitution);
        doc2.Body.InnerHtml = html.ToString();
    }

只读取第一个链接。 我不知道这是怎么回事..

2 个答案:

答案 0 :(得分:2)

此代码在主线程上运行,而不是由于Invoke调用而在您的工作线程上运行。所以是的,它会在开始运行时阻止UI,Speak()需要时间。使用BeginInvoke并没有解决这个问题。

首先在List<string>中收集字符串,这不应超过一小部分秒。将该清单传递给工人说话。

使用SpeakAsync()也可以工作,避免使用该线程并使其更容易中止说话,但是跟踪你在页面上的位置会更加困难。通过迭代器btw彻底解决,查看您最喜爱的C#语言书中的 yield 关键字。

答案 1 :(得分:1)

不允许从与您尝试更改的控件关联的调度程序线程以外的线程更改用户界面。您需要使用Control.BeginInvoke从其他线程完成更新。