从线程向表单添加标签

时间:2014-01-31 13:26:14

标签: vb.net multithreading delegates

我正在开发一个VB.Net项目,我正在尝试从一个在后台运行的线程(一个必要的邪恶)中为我的表单添加一个标签。

我创建了全局变量SmallTextLabel(Type:Label)并分配了我想要的所有属性。我现在只是想使用Me.Controls.Add(SmallTextLabel)将其添加到我的表单中。每次运行此代码时,它都会告诉我必须调用控件。我在屏幕上尖叫,这就是我正在尝试做的事情,但它会听吗?!

无论如何,我在过去的4个小时里一直在搜索互联网,并且还没有设法解决这个问题,所以请...那里的任何人都可以为我发光吗?

这是我目前使用AddSmallLabelControl(SmallTextLabel)调用的代码

修改后的示例

Private Delegate Sub AddSmallLabelControlHandler(ByVal test As Label)
Private Sub AddSmallLabelControl(ByVal test As Label)
    If Me.InvokeRequired Then
        Dim d As New AddSmallLabelControlHandler(AddressOf AddSmallLabelControl)
        Me.Invoke(d, test)
    Else
        Me.Controls.Add(test)
        test.BringToFront()
    End If
End Sub

Private Sub ShowScanConfirmationLabel()
    Dim SmallTextLabel As New Label
    Dim TahomaSmall As New Font("Tahoma", 20, FontStyle.Bold)

    With SmallTextLabel
        .Height = 40
        .Width = 312
        .Location = New Point(3, 121)
        .BackColor = Color.Green
        .Text = "Testing"
        .TextAlign = ContentAlignment.TopCenter
        .Font = TahomaSmall
    End With

    End With
    Call AddSmallLabelControl(SmallTextLabel)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim MakeLabelsVisibleHandler As New ThreadStart(AddressOf MakeLabelsVisible)
    Dim timerThread As New Thread(MakeLabelsVisibleHandler)
    timerThread.Start()
End Sub

Private Sub MakeLabelsVisible()
    ShowScanConfirmationLabel()
End Sub

2 个答案:

答案 0 :(得分:2)

好的,我在您的代码中发现了一点但严重的不一致,这可能会导致您实际上没有运行调用......

假设您在工作线程中初始化Label,那么检查Me.SmallLabel.InvokeRequired将返回False,因为它已在同一个线程上创建。因此,您的程序实际上永远不会调用Me.Invoke(...)

当您尝试访问在另一个线程上创建的表单控件时,应检查该表单是否需要调用。在您的情况下:Me.InvokeRequired

请尝试使用此代码:

Private Delegate Sub AddSmallLabelControlHandler(ByVal test As Label)
Private Sub AddSmallLabelControl(ByVal test As Label)
    If Me.InvokeRequired Then
        Dim d As New AddSmallLabelControlHandler(AddressOf AddSmallLabelControl)
        Me.Invoke(d, test)
    Else
        Me.Controls.Add(test)
        ' If you need .BringToFront use it here:
        test.BringToFront()
        ' But like this it is called every time you add a label of course.
    End If
End Sub

修改 关于.NET CF

因此,紧凑型框架上的某些独特方式似乎Invoke 表现。即,它希望调用EventHandler别无其他

来源:MSDN

在这种情况下,我们必须重构我们的代码:

首先,因为我们必须使用EventHandler,我们需要使用它的签名EventHandler(Object sender, EventArgs e)

因此,当我们需要向目标程序发送一个新的Label时,一个简单的解决方案是将其放入sender并随后进行转换。

但谨慎的做法是实现自己的EventArgs类,其中包含一个Control并投射该类。

所以这里示例代码的VB变体显示了如何调用CF上的控件

' Start the worker thread
Private Sub InitWorker()
    Dim trdWorker As New Thread(New ThreadStart(AddressOf WorkerThread))
    trdWorker.Start()
End Sub

Private Sub WorkerThread()
    Dim testLabel As New Label() With {
        .Name = "TestLabel",
        .Text = "Test Label",
        .Location = New Point(5, 30)
    }
    ' Create your EventArgs containing the control you wish to add
    Dim e As New AddControlEventArgs(testLabel)

    ' Create EventHandler
    Dim ehnd As New EventHandler(AddressOf AddControl)

    ' Invoke EventHandler with EventArgs (don't need sender as of now)
    Me.Invoke(ehnd, Nothing, e)
End Sub

' Define your custom EventArgs to hold one Control
Public Class AddControlEventArgs : Inherits EventArgs
    Public Sub New(p_control As Control)
        m_control = p_control
    End Sub
    Private m_control As Control
    Public ReadOnly Property Control As Control
        Get
            Return m_control
        End Get
    End Property
End Class

Private Sub AddControl(sender As Object, e As EventArgs)
    ' Cast EventArgs to your custom EventArgs
    Dim ec As AddControlEventArgs = DirectCast(e, AddControlEventArgs)
    Me.Controls.Add(ec.Control)

    ' Still, do you need this?
    ec.Control.BringToFront()
End Sub

最后的一些说明:

  • 我的解决方案与MSDN源中的解决方案有一个基本方式不同。 MSDN解决方案存储它希望在类中的中性字段上调用的消息,我创建自己的EventArgs来保存消息(在我们的案例a Control

  • 我没有安装CF环境,因此我无法在CF环境中测试解决方案 。有一些反馈会很棒,这是否真的解决了这个问题

  • 您应该使用compact-framework标记您的帖子,因为CF上的解决方案可能与普通解决方案有根本的不同(由此困境证明)

答案 1 :(得分:0)

通过在调用中移动标签的创建,代码运行没有问题。感谢@MrPaulch对此问题的所有帮助。请问你最后的评论。

Private Delegate Sub AddSmallLabelControlHandler(ByVal test As String)
Private Sub AddSmallLabelControl(ByVal test As String)
    If Me.InvokeRequired Then
        Dim d As New AddSmallLabelControlHandler(AddressOf AddSmallLabelControl)
        Me.Invoke(d, test)
    Else
        Dim SmallTextLabel As New Label
        Dim TahomaSmall As New Font("Tahoma", 20, FontStyle.Bold)

        With SmallTextLabel
            .Height = 40
            .Width = 312
            .Location = New Point(3, 121)
            .BackColor = Color.Green
            .Text = test
            .TextAlign = ContentAlignment.TopCenter
            .Font = TahomaSmall
        End With            
        Me.Controls.Add(SmallTextLabel)
        test.BringToFront()
    End If
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim MakeLabelsVisibleHandler As New ThreadStart(AddressOf MakeLabelsVisible)
    Dim timerThread As New Thread(MakeLabelsVisibleHandler)
    timerThread.Start()
End Sub

Private Sub MakeLabelsVisible()
    Call AddSmallLabelControl("This now works")
End Sub