Как безопасно вызвать элемент управления из другого потока, используя Timers.Timer
Я прочитал различные посты и сделал учебный проект, но он не работает. Форма имеет кнопку и текстовое поле с текстом по умолчанию "Обновлено 0 раз". При нажатии кнопки запускается таймер и каждый раз обновляется текст с количеством раз, которое текст был обновлен.
Исключение межпотоковых вызовов не выдается, но при вызове текстового поля, его.Text = "", текст обновляется, но не текстовое поле в форме. И InvokeRequired всегда ложно.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Here the textBox.Text = "Updated 0 times."
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer()
End Sub
Delegate Sub UpdateTextInvoke(ByVal new_text As String)
Public Sub UpdateText(ByVal new_text As String)
'Here the textBox.Text = ""
Dim txtB As TextBox = Me.TextBox1
'InvokeRequired always = False.
If txtB.InvokeRequired Then
Dim invk As New UpdateTextInvoke(AddressOf UpdateText)
txtB.Invoke(invk, New Object() {new_text})
Else
'The value of this text box is updated, but the text on the form TextBox1 never changes
txtB.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer
Private Shared counter As Integer
Public Shared Sub StartTimer()
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
Form1.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class
РЕШЕНО В классе TimerTest добавлен этот код "Private Shared myform As Form1 = Form1", затем изменен "Form1.UpdateText" на "myform.UpdateText"
1 ответ
Как указано в комментариях, вы используете функцию экземпляра формы по умолчанию в VB.Net. Вы можете передать экземпляр формы в класс TimerTest и заменить ссылку на Form1 на экземпляр.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer(Me)
End Sub
Public Sub UpdateText(new_text As String)
If TextBox1.InvokeRequired Then
Dim invk As New Action(Of String)(AddressOf UpdateText)
TextBox1.Invoke(invk, {new_text})
Else
TextBox1.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer()
Private Shared counter As Integer
Private Shared instance As Form1
Public Shared Sub StartTimer(formInstance As Form1)
instance = formInstance
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
instance.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class