Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从另一个线程VB.net在主线程上打开窗体_.net_Vb.net_Winforms - Fatal编程技术网

从另一个线程VB.net在主线程上打开窗体

从另一个线程VB.net在主线程上打开窗体,.net,vb.net,winforms,.net,Vb.net,Winforms,我有一个在我们的软件(VB.NET)中运行的自定义通知。通知将在新线程中打开,因此当通知淡入或淡出时,用户仍可以与软件交互 我希望用户能够单击通知并在主线程上打开表单。当我使用普通的Form.Show()方法时,它会在通知所在的线程上打开,然后在通知关闭时关闭 如何让不同的线程在主线程上执行sub 我的代码正在更新 这将启动通知 Public Sub StartNotificationThread(sender, e) 'started from main thread Try

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

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

如何让不同的线程在主线程上执行sub

我的代码正在更新

这将启动通知

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

这为您提供了一个开始的想法: (但我要说的是,最好不要只是问,而是展示你想做什么——说编码——或者通过几行代码给出你想法的一个小场景)

然后,您可以按如下方式从每个线程调用:

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()
要显示主线程形式,您可以使用以下方法:

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()

如果要封送对表单中UI线程的方法调用,通常会对表单或其某个控件调用
Invoke
,以调用拥有该表单的线程上的方法。在本例中,这不是一个选项,因为表单不属于UI线程

在表单以外的类中,通常使用
SynchronizationContext
类,在创建对象时获取
当前值,然后在次线程上执行的代码中使用该值。这是你应该在这里做的,但有一个变化

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

主要(启动)表格:

导入系统线程
公开课表格1
'UI线程的SynchronizationContext。
私有uiContext作为SynchronizationContext=SynchronizationContext.Current
私有子按钮1\u单击(发送者作为对象,e作为事件参数)处理按钮1。单击
'在辅助线程上显示新的Form2实例。
调用新线程(Sub()调用新Form2(uiContext).ShowDialog()).Start()函数
端接头
末级
中学表格:

导入系统线程
公开课表格2
'UI线程的SynchronizationContext。
作为SynchronizationContext的专用uiContext
公共子新建(uiContext作为SynchronizationContext)
'设计器需要此调用。
初始化组件()
'在InitializeComponent()调用之后添加任何初始化。
Me.uiContext=uiContext
端接头
私有子按钮1\u单击(发送者作为对象,e作为事件参数)处理按钮1。单击
'在Form1的默认实例上显示文本。
'由于打开的Form1实例不属于当前线程,因此不会看到此文本。
Form1.Label1.Text=Date.Now.ToString()
端接头
私有子按钮2\u单击(发送者作为对象,e作为事件参数)处理按钮2。单击
'在UI线程上显示新的Form3实例。
uiContext.Send(子(状态)调用New Form3().Show(),无)
关闭()
端接头
末级
第三级:

公共类表单3
私有子按钮1\u单击(发送者作为对象,e作为事件参数)处理按钮1。单击
'在Form1的默认实例上显示文本。
'将看到此文本,因为打开的Form1实例属于当前线程。
Form1.Label1.Text=Date.Now.ToString()
端接头
末级
主窗体需要一个
按钮
和一个
标签
,次窗体需要两个
按钮
,三级窗体需要一个
按钮

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


然后,您可以单击辅助窗体上的第二个
按钮
,在UI线程上创建和显示第三个窗体,并关闭辅助窗体。通过单击
按钮
并查看主表单更新上的
标签
,您可以向自己证明它属于UI线程。这表明当前线程的默认实例是当前显示的实例,因此当前线程必须是UI线程。

您好,谢谢您的帮助,但它似乎仍在另一个线程的子线程上运行。我将用更多的代码更新我的主要问题。因此,您可以将这两个方法放在主线程形式中,或者您可以从通知控件/直接从中执行,正如las代码所示:(今天运气不太好。当我从通知线程Dim T作为Threading.thread=New Threading.thread(Sub()运行此代码时)从abo调用(Sub()About.Show()End Sub)End Sub)T.Start()