VB.net、调用、委托和线程。不知道如何跨类使用它们
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18730013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
VB.net, Invoke, delegates, and threading. Can't figure out how to use them across classes
提问by Finch042
Long story short, I'm having a hell of a time trying to figure out how to use invoke and/or delegates to update the userform from a separate class when using threading. I'm quite sure it's something silly and obvious to someone with more experience. I know a delegate is probably required, but all my efforts seem to only work when it's being called from main thread. I've been looking around the internet for half the day, and there's just something I'm not getting.
长话短说,我有很多时间试图弄清楚在使用线程时如何使用调用和/或委托从单独的类更新用户窗体。我很确定这对于有更多经验的人来说是愚蠢而明显的。我知道可能需要委托,但我所有的努力似乎只有在从主线程调用时才有效。我已经在互联网上浏览了半天,但我没有得到一些东西。
Here's some pseudo-code as an example:
下面以一些伪代码为例:
This option works:
此选项有效:
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
While this (one of my 1000 efforts of slightly different variation) does not. Practically speaking, I just tried to separate one of the subs into its own class for this example, but it's otherwise the same as I could make it:
而这(我的 1000 次尝试中略有不同的变化之一)没有。实际上,在这个例子中,我只是试图将一个 subs 分离到它自己的类中,但在其他方面与我可以做到的相同:
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
From what I can tell, it appears that the if statement for invokerequired in the Sub "SetLabelText" never gets triggered. My best guess is that I'm not referring to the userform correctly when checking for the invokerequired parameter? Or I need to feed something else to the delegate? I'm just getting frustrated with messing around with the million little variables I might be getting wrong. Thanks in advance for any help you can provide and let me know if you need more info.
据我所知,子“SetLabelText”中的 invokerequired 的 if 语句似乎永远不会被触发。我最好的猜测是在检查 invokerequired 参数时我没有正确地指代用户表单?或者我需要给代表提供其他东西?我只是因为弄乱了可能会出错的数百万个小变量而感到沮丧。预先感谢您提供的任何帮助,如果您需要更多信息,请告诉我。
采纳答案by Jay Taplin
I'm not certain I understand what you are trying to do, but building upon your code, you can set the label safely ("thread-safely") by using the following code:
我不确定我是否理解您要做什么,但是基于您的代码,您可以使用以下代码安全地(“线程安全地”)设置标签:
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)
I created a Delegate called "SetText"; when the form calls the count function in your class, you can pass an instance of the delegate that references the SetLabelText method. Within that method you can then safely set the label text either directly or indirectly via Invoke along with a new instance of the delegate.
我创建了一个名为“SetText”的委托;当表单在您的类中调用 count 函数时,您可以传递引用 SetLabelText 方法的委托实例。在该方法中,您可以直接或间接通过 Invoke 以及委托的新实例安全地设置标签文本。
Something you definitely don't want to do is reference your form from your class(i.e. "form1.SetLabelText(CStr(i))"); that can create a real nightmare as the project grows in size and requirements change!
您绝对不想做的是从您的类中引用您的表单(即“form1.SetLabelText(CStr(i))”);随着项目规模的增长和需求的变化,这可能会造成真正的噩梦!
If I've misunderstood your question or not answered it properly, please do post back.
如果我误解了您的问题或没有正确回答,请回帖。
回答by jcwrequests
First off I would suggest using the Task Parrallel Library instead of threads. It's easier to understand and work with. For example,
首先,我建议使用任务并行库而不是线程。它更容易理解和使用。例如,
Dim countTask as New Task(Sub() Count(10))
Dim displayTask = countTask.ContinueWith(Sub()
Me.Invoke(Sub() Label.Text = "10"
End Sub)
countTask.Start()
This example assumes you are calling this from the form itself. You can use this method to return values from the first task to the second. If you need a more detail example and want more examples check out http://msdn.microsoft.com/en-us/library/hh228603.aspx. If you need further help I can always throw something up on GitHub or blog about it. Good Luck.
此示例假定您是从表单本身调用它。您可以使用此方法将值从第一个任务返回到第二个任务。如果您需要更详细的示例并想要更多示例,请查看http://msdn.microsoft.com/en-us/library/hh228603.aspx。如果您需要进一步的帮助,我可以随时在 GitHub 或博客上提出相关内容。祝你好运。