Abhishek
Abhishek

Reputation: 997

Accessing and changing winform webbrowser from thread

I am working on the Windows app, in which i have a tabControl in which user can open multiple tab its just like IE. Now i have to access the selected tab and then have to perform some operation on the opened document.

I am able to access it but after accessing the selected tab and performing the operation the

application becomes hang while i am using another thread to perform this task.

Please suggest how should i do it.

I am using .net 4.0. C#

See Below code, This code is on the button click

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

And this is the Thread Method to invoke the operation

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


        }));

Now please provide some useful link...

This is another approach suggested by you guys..

Declaring delegate

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

On Form Load

  public Form1()
    {
        InitializeComponent();

        // initialise the delegate to point to an implemntation

        highLightBrowsercontent = new HighlightBrowsercontent(OnHighLightContent);

    }

On button click on which i want to read out the content as well as want to highlight the links.

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

        this.backgroundWorker2.RunWorkerAsync(links);
    }

And finally this the Process i want to perform .

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

It is reading only first link. i don't know what is going with this..

Upvotes: 1

Views: 1173

Answers (2)

Hans Passant
Hans Passant

Reputation: 941437

This code runs on the main thread, not your worker thread due to the Invoke call. So yes, it will block the UI when it starts running, Speak() takes time. Using BeginInvoke does not solve that.

Collect the strings first in a List<string>, that should not take more than a fraction of second. Pass that list to the worker to speak.

Using SpeakAsync() could work too, avoiding the thread and making it much easier to abort speaking but it will be harder to keep track of where you are on the page. Cleanly solved by an iterator btw, review the yield keyword in your favorite C# language book.

Upvotes: 2

Tudor
Tudor

Reputation: 62439

It is not permitted to change the user interface from a thread other than the dispatcher thread associated to the control you are trying to change. You will need to use Control.BeginInvoke to accomplish an update from a different thread.

Upvotes: 1

Related Questions