.net - 从不同的线程 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 线程。
在表单以外的类中,您通常使用SynchronizationContext
类,在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
初级表格需要 aButton
和 a Label
,二级表格需要两个Buttons
,第三级表格需要一个Button
。
当您单击Button
主窗体上的 时,它将在辅助线程上创建和显示辅助窗体并将其传递SynchrinizationContext
给 UI 线程。您可以向自己证明辅助表单由辅助线程拥有,因为它是通过调用显示的,ShowDialog
但您仍然可以访问主表单。此外,您可以单击第一个Button
,Label
主窗体上的 将不受影响。这是因为代码是在辅助线程上执行的,因此该线程的默认实例Form1
不是显示的实例。
然后,您可以单击Button
辅助窗体上的第二个,以在 UI 线程上创建和显示第三个窗体并关闭辅助窗体。Button
您可以通过单击并查看Label
主表单更新来向自己证明它归 UI 线程所有。那说明当前线程的默认实例是当前显示的实例,所以当前线程一定是UI线程。
推荐阅读
- r - 使用字符向量对 data.table 中的行和列进行子集化
- excel - 时间表加班时间加起来
- java - Java 支持 WS-Fed 与 SAML 作为登录协议
- c# - 检查 Windows 服务是否可以从桌面应用程序访问网络共享(UNC 路径)
- android - 如果 1dp 是 1 英寸的 160 分之一,为什么在每个 android 设备上都不一样,比如 mm?
- android - 下载 Play Store 版本时应用程序停止,但是当构建变体直接在手机上运行时,相同版本可以完美运行
- python - 使用python参数化的postgresql select语句
- django - 按用户过滤不是在另一个模型查询集中使用 Q 的员工
- php - 在php中的HTML表格多维数组中显示数组数据
- java - Java 默认为 BufferedReader 使用什么编码/字符集?