【问题标题】:VB.net, Invoke, delegates, and threading. Can't figure out how to use them across classesVB.net、调用、委托和线程。不知道如何跨类使用它们
【发布时间】:2013-09-10 22:51:51
【问题描述】:

长话短说,在使用线程时,我一直在试图弄清楚如何使用调用和/或委托从单独的类更新用户表单。我很确定这对于有更多经验的人来说是愚蠢而明显的。我知道可能需要委托,但我所有的努力似乎只有在从主线程调用时才有效。我已经在互联网上看了半天,只是有些东西我没有得到。

这里有一些伪代码作为例子:

此选项有效:

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 次略有不同的变化之一)没有。实际上,对于这个示例,我只是尝试将其中一个 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

据我所知,子“SetLabelText”中的invokerequired 的if 语句似乎永远不会被触发。我最好的猜测是我在检查 invokerequired 参数时没有正确引用用户表单?或者我需要向代表提供其他东西?我只是对弄乱我可能弄错的数百万个小变量感到沮丧。提前感谢您提供的任何帮助,如果您需要更多信息,请告诉我。

【问题讨论】:

  • 您不能在线程上运行的代码中使用“Form1”。它是一个类型名称,而不是一个对象名称,这通常是 vb.net 程序员的主要心理障碍。在线程代码中分崩离析,您将获得 Form1 类的 new 实例,而不是用户正在查看的实例。如果您急于弄清楚如何传递对对象的引用,请使用 Application.OpenForms(0)。
  • 也很有用!我会记住的。谢谢。

标签: vb.net multithreading invoke


【解决方案1】:

我不确定我是否理解您要执行的操作,但是基于您的代码,您可以使用以下代码安全地设置标签(“线程安全”):

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))”);随着项目规模的扩大和需求的变化,这可能会造成真正的噩梦!

如果我误解了您的问题或没有正确回答,请回复。

【讨论】:

  • 主要是想举一个我能找到的最简单的例子(使用我之前遇到的一些代码,在之前搜索答案时)。这正是我所需要的,希望我能够相应地调整它。非常感谢!
【解决方案2】:

首先,我建议使用任务并行库而不是线程。它更容易理解和使用。例如,

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 或博客上发布一些关于它的内容。祝你好运。

【讨论】:

  • 奇怪的是我第一次听说这个,它最终可能会帮助我解决我的问题所涉及的实际项目。我正在使用线程池和同步锁来收集有关文件的信息并将其写入文本文件。长话短说,线程不必按照我需要将信息写入文本文件的顺序返回,而且我不确定是否有比 Monitor.Wait/Minitor.Pulse 等更优雅的方式来处理它. 这可能需要我一段时间,但您提供的链接似乎可能更快/更好。如果你有时间,我真的很感激一些指导。
  • 无论哪种方式,即使您最终没有解决任何其他问题,也非常感谢您提供更多信息/替代方案。
  • 您可能还想查看 Reactive Extensions jensbits.com/2012/01/23/…。我一直在项目中广泛使用 TPL 和 RX,它允许我编写更多的声明性代码。我将尝试在 github 上放置一个博客条目或示例。在 github 上,我在 github.com/jcwrequests 或我的博客在 wysnet.blogspot.com/。如果你有一个 github 帐户并在那里发布一些问题和示例,我总是可以在我的回复中进行拉取请求。无论如何祝你好运。
猜你喜欢
  • 1970-01-01
  • 2014-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 2015-11-18
相关资源
最近更新 更多