Reputation: 55
I have problem with inputting random letter in textbox. Here's code:
Imports Microsoft.VisualBasic
Imports System.Timers
Public Class Form1
Dim SlovaTimer As Timer
Dim AbecedaArray() As Char = {"A", "B", "C", "Č", "Ć", "D", "Dž", "Đ", "E", "F", "G", "H" _
, "I", "J", "K", "L", "Lj", "M", "N", "Nj", "O", "P", "R" _
, "S", "Š", "T", "U", "V", "Z", "Ž"}
Dim counter As Integer = 0
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
SlovaTimer = New Timer(200)
AddHandler SlovaTimer.Elapsed, New ElapsedEventHandler(AddressOf Handler)
SlovaTimer.Enabled = True
Button1.Enabled = False
End Sub
Private Sub Handler(ByVal sender As Object, ByVal e As ElapsedEventArgs)
If counter = 11 Then
SlovaTimer.Stop()
Button2.Enabled = False
Else
Dim ctrl As Control
For Each ctrl In Me.Controls
If (ctrl.GetType() Is GetType(TextBox)) Then
Dim txt As TextBox = CType(ctrl, TextBox)
If txt.Tag = counter Then
Dim random As New Random
Dim randletter As Integer = random.Next(0, 29)
Dim letter As String
letter = AbecedaArray(randletter)
txt.Text = letter
End If
End If
Next
SlovaTimer.Start()
End If
Here's error: Cross-thread operation not valid: Control 'TextBox1' accessed from a thread other than the thread it was created on. Any idea? Thanks!
Upvotes: 0
Views: 205
Reputation: 82474
You are getting this exception because you are trying to change the text of a Textbox in a thread that is not the UI thread.
In this case, you can replace the System.Timers.Timer
with System.Windows.Forms.Timer
as Plutonix suggested in his comment, and this will probably solve the problem.
However, you should know how to handle these exceptions if you come across them in the future.
To make a cross-thread call to a UI control in winforms you need to use Invoke
.
Create a method for setting the text of a textbox, and a delegate to that method:
Delegate Sub SetTextCallback(txt as TextBox, newString As String)
Private Sub SetText(txt as TextBox, newString As String)
' Calling from another thread? -> Use delegate
If txt.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
' Execute delegate in the UI thread, pass args as an array
Me.Invoke(d, New Object() {txt, newString})
Else ' Same thread, assign string to the textbox
txt.Text = newString
End If
End Sub
Now, as you can see, this method actually invokes itself if the property InvokeRequired
of the textbox
returns True
. if it returns False
, it means that you can safely set the Text
of the textbox.
Upvotes: 2