locked
VB.Net BackgroundWorker1 Error: InvalidCastException was unhandled by user code - WebBrowser1.Document.GetElementById RRS feed

  • Question

  • I have the below code, works but when I move it to a BackgroundWorker1 I get an error: InvalidCastException was unhandled by user code.  Thoughts?

    Working code: but don't want code in UI

     Private Sub ButtonSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSend.Click
    
         
            Dim var As Integer
            Dim startVal As Integer
            Dim endVal As Integer
            startVal = 1
            endVal = (TextBoxRepeat.Text)
    
            For var = startVal To endVal
                WebBrowser1.Document.GetElementById("Name").SetAttribute("value", TextBoxName.Text)
                WebBrowser1.Document.GetElementById("Email").SetAttribute("value", TextBoxeMail.Text)
                WebBrowser1.Document.GetElementById("Country").SetAttribute("value", TextBoxContry.Text)
                WebBrowser1.Document.GetElementById("Comments").SetAttribute("value", TextBoxComments.Text)
                WebBrowser1.Document.GetElementById("ctl10").InvokeMember("click")
                System.Threading.Thread.Sleep(TextBoxRepeat.Text * 1000)
            Next var
        End Sub

    Non-Working Code, with Error:

    Any Help is greatly appreciated!

    Sunday, July 22, 2012 4:14 PM

Answers

  • Thanks Armin, can you give me a quick example. I turned Option Strict On. Fixed all errors other than the sleep, is that your suggestion to use a timer rather than sleep? and my concern would be take out the BGW would have the code in the UI. I thought this would hang the application on the repeat.

    Drop a Timer from the toolbox on the Form. Double-click on it and handle it's Tick event. There you can add the 5 lines you currently have inside the loop.

    Whenever TextBoxRepeat changes (handle it's TextChanged event), you can update the Interval of the Timer. Instead of a Textbox you can use a NumericUpDown control so that input validation is not required (handle the ValueChanged event then).

    You're right the UI would hang, however, how long do these 5 lines take to execute? 1 ms? That's not a noticable hang.


    Armin

    • Proposed as answer by Frank L. Smith Sunday, July 22, 2012 7:35 PM
    • Marked as answer by jimbrown.net Monday, July 23, 2012 12:44 PM
    Sunday, July 22, 2012 5:09 PM
  • If you've never used a timer as a part of a loop before, it can seem a little strange.  Here's your code in a timer tick event:

      Private Sub ButtonSend_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ButtonSend.Click
        Doc = WebBrowser1.Document
        Timer1.Interval = 1
        Timer1.Start()
      End Sub
      Dim Cnt As Integer
      Dim Doc As HtmlDocument
      Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
        Timer1.Stop()
        Cnt += 1
        If Cnt > CInt(TextBoxRepeat.Text) Then Cnt = 0 : Return
        Dim Elements() As String = {"Name", "Email", "Country", "Comments"}
        Dim Values() As String = {TextBoxName.Text, TextBoxMail.Text, TextBoxCountry.Text, TextBoxComments.Text}
        For I As Integer = 0 To TBs.Length - 1
          Doc.GetElementById(Elements(I)).SetAttribute("value", Values(I))
        Next
        Doc.GetElementById("ct110").InvokeMember("click")
        Timer1.Interval = CInt(TextBoxRepeat.Text) * 1000
        Timer1.Start()
      End Sub






    • Edited by JohnWein Sunday, July 22, 2012 6:49 PM
    • Proposed as answer by Frank L. Smith Sunday, July 22, 2012 7:35 PM
    • Marked as answer by jimbrown.net Monday, July 23, 2012 12:44 PM
    Sunday, July 22, 2012 6:25 PM

All replies

  • First step is switching Option Strict On, look at each compile error and think about how to fix it.

    Second step: Controls shall only be access from the Thread that created them. It is invalid to access them from the BackgroundWorker. If it's really necessary to access a WebBrowser from the BGW, you must create a new one in the worker. Looking at your code, it may be a better solution to do without the worker. Instead, add a (Winforms) Timer and do the job in it's Tick event.


    Armin

    Sunday, July 22, 2012 4:27 PM
  • Thanks Armin, can you give me a quick example. I turned Option Strict On. Fixed all errors other than the sleep, is that your suggestion to use a timer rather than sleep? and my concern would be take out the BGW would have the code in the UI. I thought this would hang the application on the repeat.

    Sunday, July 22, 2012 5:01 PM
  • Thanks Armin, can you give me a quick example. I turned Option Strict On. Fixed all errors other than the sleep, is that your suggestion to use a timer rather than sleep? and my concern would be take out the BGW would have the code in the UI. I thought this would hang the application on the repeat.

    Drop a Timer from the toolbox on the Form. Double-click on it and handle it's Tick event. There you can add the 5 lines you currently have inside the loop.

    Whenever TextBoxRepeat changes (handle it's TextChanged event), you can update the Interval of the Timer. Instead of a Textbox you can use a NumericUpDown control so that input validation is not required (handle the ValueChanged event then).

    You're right the UI would hang, however, how long do these 5 lines take to execute? 1 ms? That's not a noticable hang.


    Armin

    • Proposed as answer by Frank L. Smith Sunday, July 22, 2012 7:35 PM
    • Marked as answer by jimbrown.net Monday, July 23, 2012 12:44 PM
    Sunday, July 22, 2012 5:09 PM
  • Thanks,  but I had a repeate and a delay or sleep.  so if doing the repeate 100 times with a sleep of 60 seconds the app would hang. 

    you have to remember I have working code in the UI,  and my sleep.  your suggestion is to just change out the sleep for timer.  correct?   I really think I need a BGW or a thread. 

    Sunday, July 22, 2012 5:36 PM
  • "I really think I need a BGW or a thread."

    "your suggestion is to just change out the sleep for timer"

    You're not getting it.  When you get rid of sleep and use a timer instead, your UI won't hang.

    Sunday, July 22, 2012 5:57 PM
  • If you've never used a timer as a part of a loop before, it can seem a little strange.  Here's your code in a timer tick event:

      Private Sub ButtonSend_Click(ByVal sender As Object, ByVal e As EventArgs) Handles ButtonSend.Click
        Doc = WebBrowser1.Document
        Timer1.Interval = 1
        Timer1.Start()
      End Sub
      Dim Cnt As Integer
      Dim Doc As HtmlDocument
      Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
        Timer1.Stop()
        Cnt += 1
        If Cnt > CInt(TextBoxRepeat.Text) Then Cnt = 0 : Return
        Dim Elements() As String = {"Name", "Email", "Country", "Comments"}
        Dim Values() As String = {TextBoxName.Text, TextBoxMail.Text, TextBoxCountry.Text, TextBoxComments.Text}
        For I As Integer = 0 To TBs.Length - 1
          Doc.GetElementById(Elements(I)).SetAttribute("value", Values(I))
        Next
        Doc.GetElementById("ct110").InvokeMember("click")
        Timer1.Interval = CInt(TextBoxRepeat.Text) * 1000
        Timer1.Start()
      End Sub






    • Edited by JohnWein Sunday, July 22, 2012 6:49 PM
    • Proposed as answer by Frank L. Smith Sunday, July 22, 2012 7:35 PM
    • Marked as answer by jimbrown.net Monday, July 23, 2012 12:44 PM
    Sunday, July 22, 2012 6:25 PM
  • Thanks,  I rewote to use the timer:

     Private Sub ButtonSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSend.Click
    
            Dim var As Integer
            Dim startVal As Integer
            Dim endVal As Integer
            startVal = 1
            endVal = CInt((TextBoxRepeat.Text))
    
            For var = startVal To endVal
                WebBrowser1.Document.GetElementById("Name").SetAttribute("value", TextBoxName.Text)
                WebBrowser1.Document.GetElementById("Email").SetAttribute("value", TextBoxeMail.Text)
                WebBrowser1.Document.GetElementById("Country").SetAttribute("value", TextBoxContry.Text)
                WebBrowser1.Document.GetElementById("Comments").SetAttribute("value", TextBoxComments.Text)
                'WebBrowser1.Document.GetElementById("ctl10").InvokeMember("click")
                Timer1.Interval = CInt((CDbl(TextBoxDelay.Text) * 1000)) 'In Seconds
    
            Next var
    
    
    
        End Sub

    and it does not hang the UI.  thanks,  unsure why anyone would use a sleep then.  anyway to test I added a simple writeline to see the loop is working and get the same Error: InvalidCastException was unhandled.  thoughts?

    Sunday, July 22, 2012 6:25 PM
  • Thanks,  but I had a repeate and a delay or sleep.  so if doing the repeate 100 times with a sleep of 60 seconds the app would hang. 

    you have to remember I have working code in the UI,  and my sleep.  your suggestion is to just change out the sleep for timer.  correct?   I really think I need a BGW or a thread. 

    Remove Thread.Sleep. The action is already done in intervals by using a Timer. It's executed each time the Timer ticks. Between the ticks, the UI is responsive.

    Armin

    Sunday, July 22, 2012 6:34 PM
  • Right, the string "Line26 0" can not be converted to an Integer. "26" or "0" could be converted but not "Line26 0".

    EDIT: I'd use Integer.Parse() instead of CInt() because the exception (FormatException) is more appropriate then. CInt() does a lot, and the last thing it obviously attempts after parsing fails, is casting to Integer.


    Armin


    Sunday, July 22, 2012 11:15 PM
  • Thank you,  Armin!!!
    Monday, July 23, 2012 12:45 PM