繁体   English   中英

从不同线程 VB.net 在主线程上打开表单

[英]Open form on main thread from a different thread VB.net

我有一个在我们的软件 (VB.NET) 中运行的自定义通知。 通知在新线程中打开,因此当通知淡入或淡出时,用户仍然可以与软件交互。

我希望用户能够单击通知并在主线程上打开一个表单。 当我使用普通的Form.Show()方法时,它与通知在同一线程上打开,然后在通知关闭时关闭。

如何让不同的线程在主线程上做一个子线程?

我的代码目前。

这将启动通知

Public Sub StartNotificationThread(sender, e) 'started from main thread
    Try
        thread2 = New System.Threading.Thread(AddressOf Notificaition)'my notification thread

        thread2.SetApartmentState(ApartmentState.STA)
        thread2.Start()
    Catch ex As Exception
        error_form = Me.ToString
        Email_Error(sender, ex)
    End Try
End Sub

我想点击我的通知并在主线程上做这样的事情

Public Sub NotificationClicked()'launched from notification thread
    Form1.show 'Do stuff in main thread
    Me.Close()
End Sub

如果您想在窗体中编组对 UI 线程的方法调用,通常在窗体或其控件之一上调用Invoke以调用拥有它的线程上的方法。 在这种情况下,这不是一个选项,因为表单不属于 UI 线程。

在 forms 以外的类中,您通常使用SynchronizationContext class,在创建 object 时获取Current值,然后在辅助线程上执行的代码中使用它。 这就是你应该在这里做的,但有一个变化。

不同之处在于您无法在表单本身中获取SynchronizationContext.Current ,因为它是在辅助线程上创建的。 您需要首先在调用表单中获取SynchronizationContext.Current ,在 UI 线程上执行的代码中。 然后,当您在辅助线程上执行代码以创建并显示第二个表单时,您传入该SynchornizationContext实例,然后使用它在 UI 线程上执行代码。 这是一个简单的例子:

主要(启动)形式:

Imports System.Threading

Public Class Form1

    'The SynchronizationContext for the UI thread.
    Private uiContext As SynchronizationContext = SynchronizationContext.Current

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'Display a new Form2 instance on a secondary thread.

        Call New Thread(Sub() Call New Form2(uiContext).ShowDialog()).Start()
    End Sub

End Class

次要形式:

Imports System.Threading

Public Class Form2

    'The SynchronizationContext for the UI thread.
    Private uiContext As SynchronizationContext

    Public Sub New(uiContext As SynchronizationContext)
        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

        Me.uiContext = uiContext
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'Display text on the default instance of Form1.
        'This text will not be seen because the open Form1 instance is not owned by the current thread.
        Form1.Label1.Text = Date.Now.ToString()
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'Display a new Form3 instance on the UI thread.
        uiContext.Send(Sub(state) Call New Form3().Show(), Nothing)

        Close()
    End Sub

End Class

三级形式:

Public Class Form3

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'Display text on the default instance of Form1.
        'This text will be seen because the open Form1 instance is owned by the current thread.
        Form1.Label1.Text = Date.Now.ToString()
    End Sub

End Class

主要形式需要一个Button和一个Label ,次要形式需要两个Buttons ,第三级形式需要一个Button

当您单击主窗体上的Button时,它将在辅助线程上创建和显示辅助窗体,并将 UI 线程的SynchrinizationContext传递给它。 您可以向自己证明辅助窗体由辅助线程拥有,因为它是通过调用ShowDialog显示的,但您仍然可以访问主窗体。 此外,您可以单击第一个Button ,主窗体上的Label将不受影响。 这是因为代码在辅助线程上执行,因此该线程的Form1的默认实例不是显示的实例。

然后,您可以单击辅助窗体上的第二个Button以在 UI 线程上创建和显示第三窗体并关闭辅助窗体。 您可以通过单击Button并在主表单更新上看到Label来证明它归 UI 线程所有。 那说明当前线程的默认实例是当前显示的实例,所以当前线程一定是UI线程。

这为您提供了一个开始的想法:(但是让我说,最好不仅询问,而且显示您要做什么 - 编码口语 - 或通过一些代码行给出您想法的一个小场景)

   'It’s supposed to be inside the main form
    Sub SubToCall(otherParam As String)
        Debug.WriteLine("SubToCall called " & otherParam)
        Me.ShowDialog()
    End Sub

    Sub CallMeFromEveryWhere()
        If InvokeRequired Then
            Invoke(Sub()
                       SubToCall(" from another thread ")
                   End Sub)
        Else
            SubToCall(" from main thread ")
        End If
    End Sub

然后你可以从每个线程调用如下:

Dim T As Threading.Thread = New Threading.Thread(Sub()
                                                   MainForm.CallMeFromEveryWhere()
                                             End Sub)

T.Start()

并显示您的主线程表单,您可以使用如下:

        Dim T As Threading.Thread = New Threading.Thread(Sub()
                                                         Invoke(Sub()
                                                                    MainThreadForm.Show()
                                                                End Sub)
                                                     End Sub)
        T.Start()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM