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

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.
- Edited by jimbrown.net Sunday, July 22, 2012 5:41 PM
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.
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
- Edited by Armin Zingler Sunday, July 22, 2012 11:18 PM
Sunday, July 22, 2012 11:15 PM -
Thank you, Armin!!!Monday, July 23, 2012 12:45 PM