跨线程操作无效:ContextMenuStrip

时间:2012-03-16 09:56:07

标签: vb.net multithreading

我遇到'线程'问题。我希望有两个'形式'在单独的过程中工作,例如,如果我从一个'形式'打开'OpenFileDialog',另一个'形式'分开工作并做一些其他事情。 (看到我的代码,我的描述很糟糕。)

我使用'线程',它工作正常。但如果我的'form'具有'ContextMenuStrip'控件,则会发生错误'跨线程操作无效'。 请帮帮我。

感谢。

=============================================== ================================== FormMain:

Public Class FormMain

Private Sub cmdShow_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdShow.Click
    Form2.ShowMe()
End Sub

End Class

=============================================== ================================== 窗体2:

Public Class Form2

'Me.ContextMenuStrip1 = New System.Windows.Forms.ContextMenuStrip(Me.components)
'Me.Panel1 = New System.Windows.Forms.Panel
'Me.Panel1.ContextMenuStrip = Me.ContextMenuStrip1


Public Shared Thread_2 As System.Threading.Thread
Public MyDefaultWindowState = FormWindowState.Normal

Private Delegate Sub dlgShowMe()
Public Sub ShowMe()
    If Thread_2 IsNot Nothing AndAlso Thread_2.ThreadState = Threading.ThreadState.Running Then
        If Me.InvokeRequired Then
            Dim d As New dlgShowMe(AddressOf Me.ShowMe)
            Me.Invoke(d)
        Else
            Show_Activate_()
        End If
    Else
        Thread_2 = New System.Threading.Thread(AddressOf Me.Show_View_)
        Thread_2.SetApartmentState(System.Threading.ApartmentState.STA)
        Thread_2.IsBackground = False
        Thread_2.Start()
    End If
End Sub

Private Sub Show_Activate_()
    Try
        Me.Enabled = True
        Me.ShowInTaskbar = True
        Me.WindowState = Me.MyDefaultWindowState

        Me.BringToFront()
        Me.Activate()
    Catch ex As Exception
        MsgBox(ex.Message, , "Show_Activate_")
    End Try
End Sub
Private Delegate Sub dlgShow_View_()
Private Sub Show_View_()
    Me.Enabled = True
    Me.ShowInTaskbar = True

    Try
        Me.ShowDialog()
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical,"Show_View_")
    End Try
End Sub


Private Sub cmdOpenFileDialog1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdOpenFileDialog1.Click
    OpenFileDialog1.ShowDialog()
End Sub

End Class

=============================================== =

这是我的源代码: http://www.mediafire.com/?m8e8i51rr51a35i [63KB]

运行'FormMain'。 点击'cmdShow'。 当'Form2'显示时。右键单击“Panel1”。 将出现'ContextMenuStrip1'。

关闭'Form2。

再次点击“cmdShow”。 当'Form2'显示时。再次右键单击“Panel1”。 但你可以看到错误...

2 个答案:

答案 0 :(得分:0)

错误是因为您尝试从不是UI线程(主线程)的线程修改GUI。

在更新UI或执行与UI相关的任何操作之前,您必须在任何控件上调用。

请考虑以下代码段:

Friend Shared Sub RaiseUiEvent(ByVal hnd As EventHandler, ByVal sender As Object, ByVal e As EventArgs)
    Dim uiRef = GlobalManager.GetInstance().UI 'uiRef is just a ref to a control of my UI

    uiRef.BeginInvoke(hnd, sender, e)     
End Sub

BeginInvoke是异步,Invoke是同步

params是:一个将被执行的委托,最终是一个传递的对象数组。

但有些事情困扰着我,为什么你想让两个表单在不同的线程中“工作”?在任何情况下,你的GUI都不应该有任何繁重的处理。

编辑:

好的,所以我明白了什么是错的:你只需要一个非模态对话框! 但是OpenFileDialog是模态的(cf C# OpenFileDialog Non-Modal possible) 这个问题与线程无关!

答案 1 :(得分:0)

您未在此部分中调用

Private Delegate Sub dlgShow_View_()
Private Sub Show_View_()
    Me.Enabled = True
    Me.ShowInTaskbar = True

    Try
        Me.ShowDialog()
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical,"Show_View_")
    End Try
End Sub

你应该把它改成:

Private Delegate Sub dlgShow_View_()
Private Sub Show_View_()
    if Me.InvokeRequired Then
        Dim d as New dlgShow_View_(adressOf Show_View_)
    else
    Me.Enabled = True
    Me.ShowInTaskbar = True

    Try
        Me.ShowDialog()
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Critical,"Show_View_")
    End Try
    End If
End Sub