将文本框更新为与 backgroundworker 不同的形式
Update textbox to a different form from backgroundworker
我有两个表格,Form1 和 Newform。 Form1 有两个按钮和一个文本框,Newform 有自己的文本框。我正在使用 settext sub 调用 backgroundworker 中的委托 sub 来更新两种形式的文本框。
Form1 中的文本框似乎正在更新,但 Newform 中的文本框没有更新。
如果我想以不同的形式更新文本框,是否缺少某些内容?
提前致谢。
Imports System.Threading
Public Class Form1
Dim stopbit As Boolean
Dim TestingComplete As Boolean
Dim ReadValue As Double
Dim FinalValue As Double
Delegate Sub SetTextCallback(ByRef Txtbox As TextBox, ByVal Txt As String)
'Thread Safe textbox update routine
Private Sub SetText(ByRef Txtbox As TextBox, ByVal Txt As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
Console.WriteLine(Txtbox.InvokeRequired & " textbox invokerequired")
If Txtbox.InvokeRequired Then
Try
'MsgBox("inside settext")
Txtbox.Invoke(New SetTextCallback(AddressOf SetText), Txtbox, Txt)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Else
Txtbox.Text = Txt
Txtbox.Update()
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
newform.Show()
End Sub
Function ReadTemp() As Double
ReadValue = ReadValue / 2
Return ReadValue
End Function
Sub Test()
Dim starttime As Integer
Dim EllapsedTime As Integer
Dim OldValue As Double = 0
Dim NewValue As Double = 0
Dim Difference As Double = 1
Dim Margin As Double = 0.1
stopbit = False
starttime = My.Computer.Clock.TickCount
Do
Thread.Sleep(200)
OldValue = NewValue
NewValue = ReadTemp()
Difference = Math.Abs(NewValue - OldValue)
SetText(Me.TextBox1, Difference.ToString)
SetText(newform.TextBox1, Difference.ToString)
newform.Refresh()
EllapsedTime = My.Computer.Clock.TickCount - starttime
Loop Until EllapsedTime > 5000 Or stopbit = True ' Or Difference < Margin
FinalValue = NewValue
TestingComplete = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
stopbit = True
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 1 To 10
ReadValue = 100000
TestingComplete = False
ThreadPool.QueueUserWorkItem(AddressOf Test)
Do
Thread.Sleep(200)
Loop Until TestingComplete = True
MsgBox("Final Value " & FinalValue)
Next
End Sub
结束Class
YourSubHere
Me.Invoke(Sub()
Form1.Textbox1.text="some text1"
Form2.Textbox2.text="some text2"
End Sub)
End Sub
或者如果它是单班轮。
Me.Invoke(Sub() Form1.Textbox1.text="some text1")
根据您的需要,您可以调用一些控件,例如:
Textbox1.invoke(Sub() Textbox1.text="some text1")
您的问题是因为您使用的是 newform
的 默认实例 。在 VB.NET 中,默认表单实例是一项功能,允许您通过表单的类型名称访问表单,而无需手动创建它的实例。
换句话说,它可以让你这样做:
newform.Show()
newform.TextBox1.Text = "Something"
...而不是以正确的方式进行操作,即:
Dim myNewForm As New newform
myNewForm.Show()
myNewForm.TextBox1.Text = "Something"
上面我们创建了一个名为 myNewForm
的 newform
的新实例。这是能够在框架(包括表单)中使用 most 对象所必需的。但是,VB.NET 通过为您创建实例来简化此行为,这就是我的第一个示例中发生的事情。
这些默认实例的问题在于它们是特定于线程的,这意味着会为您创建的每个线程创建一个新实例在中使用此行为。
因此您在执行时所指的表格:
newform.Show()
...与您在线程中引用的表单不同,因为已为其创建了一个新实例在该线程:
'This is not the same "newform" as above!
SetText(newform.TextBox1, Difference.ToString)
解决办法当然是自己创建实例,让你可以完全控制发生的事情:
Dim newFrm As New newform
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
newFrm.Show()
End Sub
...your code...
Sub Test()
...your code...
SetText(newFrm.TextBox1, Difference.ToString)
...even more of your code...
End Sub
作为旁注,您可以删除对 newform.Refresh()
和 Txtbox.Update()
的调用。这些只会通过强制表单和文本框自行重绘而造成不必要的开销,当您更改影响其 contents/design 的任何属性时,这已经完成(因此您实际上是在让它们重绘自己两次)。
此外,如果您想调用 UI 线程 更简单 并且您使用的是 Visual Studio/Visual Basic 2010 或更新的,您可以切换到使用 lambda expressions 而不是常规代表。它们更易于使用,并允许您创建可在 UI 线程上调用的整个内联方法。
为此,我编写了一个名为 InvokeIfRequired()
的扩展方法,它允许您在 UI 线程上调用 any method/function,为您查看 InvokeRequired
。它类似于您现在拥有的,只是它适用于任何控件(不仅仅是文本框)和 lambda 表达式,允许您在 UI.
上 运行 任何您想要的代码
您可以通过将模块添加到您的项目 (Add New Item... > Module
) 并将其命名为 Extensions
来使用它。然后将这段代码放入其中:
Imports System.Runtime.CompilerServices
Public Module Extensions
''' <summary>
''' Invokes the specified method on the calling control's thread (if necessary, otherwise on the current thread).
''' </summary>
''' <param name="Control">The control which's thread to invoke the method at.</param>
''' <param name="Method">The method to invoke.</param>
''' <param name="Parameters">The parameters to pass to the method (optional).</param>
''' <remarks></remarks>
<Extension()> _
Public Function InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object()) As Object
If Parameters IsNot Nothing AndAlso _
Parameters.Length = 0 Then Parameters = Nothing
If Control.InvokeRequired = True Then
Return Control.Invoke(Method, Parameters)
Else
Return Method.DynamicInvoke(Parameters)
End If
End Function
End Module
这允许您通过以下方式调用任一代码行:
Me.InvokeIfRequired(Sub() Me.TextBox1.Text = Difference.ToString())
或者调用整个代码块:
Me.InvokeIfRequired(Sub()
Me.TextBox1.Text = Difference.ToString()
newFrm.TextBox1.Text = Difference.ToString()
Me.BackColor = Color.Red 'Just an example of what you can do.
End Sub)
我有两个表格,Form1 和 Newform。 Form1 有两个按钮和一个文本框,Newform 有自己的文本框。我正在使用 settext sub 调用 backgroundworker 中的委托 sub 来更新两种形式的文本框。
Form1 中的文本框似乎正在更新,但 Newform 中的文本框没有更新。
如果我想以不同的形式更新文本框,是否缺少某些内容?
提前致谢。
Imports System.Threading
Public Class Form1
Dim stopbit As Boolean
Dim TestingComplete As Boolean
Dim ReadValue As Double
Dim FinalValue As Double
Delegate Sub SetTextCallback(ByRef Txtbox As TextBox, ByVal Txt As String)
'Thread Safe textbox update routine
Private Sub SetText(ByRef Txtbox As TextBox, ByVal Txt As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
Console.WriteLine(Txtbox.InvokeRequired & " textbox invokerequired")
If Txtbox.InvokeRequired Then
Try
'MsgBox("inside settext")
Txtbox.Invoke(New SetTextCallback(AddressOf SetText), Txtbox, Txt)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Else
Txtbox.Text = Txt
Txtbox.Update()
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
newform.Show()
End Sub
Function ReadTemp() As Double
ReadValue = ReadValue / 2
Return ReadValue
End Function
Sub Test()
Dim starttime As Integer
Dim EllapsedTime As Integer
Dim OldValue As Double = 0
Dim NewValue As Double = 0
Dim Difference As Double = 1
Dim Margin As Double = 0.1
stopbit = False
starttime = My.Computer.Clock.TickCount
Do
Thread.Sleep(200)
OldValue = NewValue
NewValue = ReadTemp()
Difference = Math.Abs(NewValue - OldValue)
SetText(Me.TextBox1, Difference.ToString)
SetText(newform.TextBox1, Difference.ToString)
newform.Refresh()
EllapsedTime = My.Computer.Clock.TickCount - starttime
Loop Until EllapsedTime > 5000 Or stopbit = True ' Or Difference < Margin
FinalValue = NewValue
TestingComplete = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
stopbit = True
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 1 To 10
ReadValue = 100000
TestingComplete = False
ThreadPool.QueueUserWorkItem(AddressOf Test)
Do
Thread.Sleep(200)
Loop Until TestingComplete = True
MsgBox("Final Value " & FinalValue)
Next
End Sub
结束Class
YourSubHere
Me.Invoke(Sub()
Form1.Textbox1.text="some text1"
Form2.Textbox2.text="some text2"
End Sub)
End Sub
或者如果它是单班轮。
Me.Invoke(Sub() Form1.Textbox1.text="some text1")
根据您的需要,您可以调用一些控件,例如:
Textbox1.invoke(Sub() Textbox1.text="some text1")
您的问题是因为您使用的是 newform
的 默认实例 。在 VB.NET 中,默认表单实例是一项功能,允许您通过表单的类型名称访问表单,而无需手动创建它的实例。
换句话说,它可以让你这样做:
newform.Show()
newform.TextBox1.Text = "Something"
...而不是以正确的方式进行操作,即:
Dim myNewForm As New newform
myNewForm.Show()
myNewForm.TextBox1.Text = "Something"
上面我们创建了一个名为 myNewForm
的 newform
的新实例。这是能够在框架(包括表单)中使用 most 对象所必需的。但是,VB.NET 通过为您创建实例来简化此行为,这就是我的第一个示例中发生的事情。
这些默认实例的问题在于它们是特定于线程的,这意味着会为您创建的每个线程创建一个新实例在中使用此行为。
因此您在执行时所指的表格:
newform.Show()
...与您在线程中引用的表单不同,因为已为其创建了一个新实例在该线程:
'This is not the same "newform" as above!
SetText(newform.TextBox1, Difference.ToString)
解决办法当然是自己创建实例,让你可以完全控制发生的事情:
Dim newFrm As New newform
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
newFrm.Show()
End Sub
...your code...
Sub Test()
...your code...
SetText(newFrm.TextBox1, Difference.ToString)
...even more of your code...
End Sub
作为旁注,您可以删除对 newform.Refresh()
和 Txtbox.Update()
的调用。这些只会通过强制表单和文本框自行重绘而造成不必要的开销,当您更改影响其 contents/design 的任何属性时,这已经完成(因此您实际上是在让它们重绘自己两次)。
此外,如果您想调用 UI 线程 更简单 并且您使用的是 Visual Studio/Visual Basic 2010 或更新的,您可以切换到使用 lambda expressions 而不是常规代表。它们更易于使用,并允许您创建可在 UI 线程上调用的整个内联方法。
为此,我编写了一个名为 InvokeIfRequired()
的扩展方法,它允许您在 UI 线程上调用 any method/function,为您查看 InvokeRequired
。它类似于您现在拥有的,只是它适用于任何控件(不仅仅是文本框)和 lambda 表达式,允许您在 UI.
您可以通过将模块添加到您的项目 (Add New Item... > Module
) 并将其命名为 Extensions
来使用它。然后将这段代码放入其中:
Imports System.Runtime.CompilerServices
Public Module Extensions
''' <summary>
''' Invokes the specified method on the calling control's thread (if necessary, otherwise on the current thread).
''' </summary>
''' <param name="Control">The control which's thread to invoke the method at.</param>
''' <param name="Method">The method to invoke.</param>
''' <param name="Parameters">The parameters to pass to the method (optional).</param>
''' <remarks></remarks>
<Extension()> _
Public Function InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object()) As Object
If Parameters IsNot Nothing AndAlso _
Parameters.Length = 0 Then Parameters = Nothing
If Control.InvokeRequired = True Then
Return Control.Invoke(Method, Parameters)
Else
Return Method.DynamicInvoke(Parameters)
End If
End Function
End Module
这允许您通过以下方式调用任一代码行:
Me.InvokeIfRequired(Sub() Me.TextBox1.Text = Difference.ToString())
或者调用整个代码块:
Me.InvokeIfRequired(Sub()
Me.TextBox1.Text = Difference.ToString()
newFrm.TextBox1.Text = Difference.ToString()
Me.BackColor = Color.Red 'Just an example of what you can do.
End Sub)