我有一个问题,我有点支持自己进入com对象和多线程的角落。我需要显示一个用户表单,据我所知它必须从UI线程调用,但是我需要从非UI线程触发它并等待用户在继续之前完成表单上的任务。
更多细节:我在一个单独的线程中在Outlook中生成一组电子邮件。创建电子邮件后,用户将查看用户表单中每封邮件的mailitem.htmlbody属性的副本。我已经研究了如何获取我正在处理消息的线程继续,有几个布尔属性,但我仍然需要弄清楚如何显示用户表单。
我试过
MessageReview.Show()
和
MessageReview.ShowDialog()
和
Dim reviewMessages As New Thread(Sub() MessageReview.Show())
reviewMessages.SetApartmentState(ApartmentState.STA)
reviewMessages.Start()
有趣的是,最后一个无声地失败了。没有显示任何表单,但也没有错误。
编辑:我刚试过这个:设置代理
Private Delegate Sub ClickReviewMessages()
'There is a button on the user form that let's you view this form as many times as needed
Private Sub ReviewMessagesClick()
If ReviewButton.InvokeRequired Then
Dim callback As New ClickReviewMessages(AddressOf ReviewMessagesClick)
ReviewButton.Invoke(callback, New Object())
Else
ReviewButton.PerformClick()
End If
End Sub
但我最终得到Parameter count mismatch.
错误。
我还在考虑尝试使用某个委托子将其绑定到表单上的按钮。尽管如此,还没有尝试过。
编辑:我只想补充说我正在尝试显示的用户表单包含一个WebBrowser控件...它似乎是一个ActiveX控件,可能就是为什么我对控件的所有大惊小怪都没有了在STA中实例化。有什么想法吗?
答案 0 :(得分:0)
您应捕获主UI线程的SynchronizationContext
,然后调用.Send()
以同步运行调用ShowDialog()
的委托,以在UI线程上显示您的表单。
创建多个UI线程会带来痛苦的世界。
答案 1 :(得分:0)
试试这个:MessageReview.Invoke(New Action(AddressOf MessageReview.ShowDialog))
根据this,Invoke
“在拥有控件底层窗口句柄的线程上执行指定的委托”。你必须传递一个委托,这样内置的Action
委托带有ShowDialog
方法的指针就可以了。
答案 2 :(得分:0)
您可以在线程中使用Invoke()在GUI线程中执行某些操作:
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim result As String
'this will block the thread until the Form MessageReview is closed/hidden
Me.Invoke(Sub()
Using frm = New MessageReview
frm.ShowDialog()
result = frm.TextBox1.Text
End Using
End Sub)
'result now contains a value
End Sub
Me
在这种情况下是表格。您可以将对Form(或任何控件)的引用传递给您的工作线程。