长话短说,我有一段时间试图弄清楚如何使用调用和/或委托在使用线程时从单独的类更新userform。对于经验丰富的人来说,我很确定这是愚蠢和明显的事情。我知道代理可能是必需的,但我所有的努力似乎只有在从主线程调用它时才有效。我一直在互联网上寻找半天,而且我只是得到了一些东西。
这里有一些伪代码作为例子:
此选项有效:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.IsBackground = True
t1.Start(100)
End Sub
Private Sub Count(ByVal Max As Object)
If TypeOf Max Is Integer Then
Count(CInt(Max))
End If
End Sub
Private Sub SetLabelText(ByVal text As String)
If Label1.InvokeRequired Then
Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)
Else
Label1.Text = text
End If
End Sub
Private Sub Count(ByVal Max As Integer)
For i = 1 To Max
SetLabelText(CStr(i))
Threading.Thread.Sleep(200)
Next
End Sub
End Class
虽然这(我的1000次尝试略有不同)之一没有。实际上,我只是尝试将其中一个sub分成这个例子中的自己的类,但它和我能做的一样:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.Start(100)
End Sub
Private Sub Count(ByVal Max As Object)
If TypeOf Max Is Integer Then
Dim class2 As New class2
class2.Count(CInt(Max))
End If
End Sub
Private Delegate Sub SetTextBoxTextInvoker(text As String)
Sub SetLabelText(ByVal text As String)
'or me.label1, form1.label1 or anything else I can try!
If Me.InvokeRequired Then
Me.Invoke(New SetTextBoxTextInvoker(AddressOf SetLabelText), _
text)
Else
Me.Label1.Text = text
End If
End Sub
End Class
Public Class class2
Sub Count(ByVal Max As Integer)
For i = 1 To Max
form1.SetLabelText(CStr(i))
Threading.Thread.Sleep(200)
Next
End Sub
End Class
据我所知,似乎Sub“SetLabelText”中的invokerequired的if语句永远不会被触发。我最好的猜测是,在检查invokerequired参数时,我没有正确引用userform?或者我需要向代表提供其他东西?我只是因为弄乱我可能出错的百万个小变量而感到沮丧。如果您需要更多信息,请提前感谢您提供的任何帮助,并告诉我们。
答案 0 :(得分:2)
我不确定我理解您要做的是什么,但在您的代码的基础上,您可以使用以下代码安全地设置标签(“线程安全”):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.IsBackground = True
t1.Start(100)
End Sub
Private Sub Count(ByVal Max As Object)
If TypeOf Max Is Integer Then
Dim class2 As New Class2
class2.Count(CInt(Max), AddressOf SetLabelText)
End If
End Sub
Private Sub SetLabelText(ByVal text As String)
If Label1.InvokeRequired Then
Label1.Invoke(New SetText(AddressOf SetLabelText), text)
Else
Label1.Text = text
End If
End Sub
End Class
Public Class Class2
Sub Count(ByVal Max As Integer, SetTextMethod As SetText)
For i = 1 To Max
SetTextMethod.Invoke((CStr(i)))
Threading.Thread.Sleep(200)
Next
End Sub
End Class
Public Delegate Sub SetText(text As String)
我创建了一个名为“SetText”的委托;当表单调用类中的count函数时,您可以传递一个引用SetLabelText方法的委托实例。在该方法中,您可以通过Invoke直接或间接安全地设置标签文本以及委托的新实例。
你绝对不想做的事情是从你的班级中引用你的表格(即“form1.SetLabelText(CStr(i))”);随着项目规模的扩大和需求的变化,这会产生真正的噩梦!
如果我误解了您的问题或没有正确回答,请回复。
答案 1 :(得分:2)
首先,我建议使用Task Parrallel Library而不是线程。它更容易理解和使用。例如,
Dim countTask as New Task(Sub() Count(10))
Dim displayTask = countTask.ContinueWith(Sub()
Me.Invoke(Sub() Label.Text = "10"
End Sub)
countTask.Start()
此示例假定您从表单本身调用此方法。您可以使用此方法将值从第一个任务返回到第二个任务。如果您需要更详细的示例并想要更多示例,请查看http://msdn.microsoft.com/en-us/library/hh228603.aspx。如果您需要进一步的帮助,我总是可以在GitHub或博客上提出一些建议。祝你好运。