我创建了一个简单的窗口表单(粘贴在下面)。现在我使用它在运行耗时的复杂操作时向用户显示等待dailog。
调用HerculesWaitForm.Show("Some Title","Some Caption...)
会像往常一样显示表单,但在调用HerculesWaitForm.Close
时仍会显示表单。我该怎么做才能解决这个问题。
Imports System.Threading
Public Class HerculesWaitForm
Inherits DevExpress.Utils.WaitDialogForm
Private Shared form As HerculesWaitForm
Private Shared _thread As Thread
Private Shared _caption As String, _title As String
Private Sub New(ByVal caption As String, ByVal title As String)
MyBase.New(caption, title)
End Sub
Private Shared Sub CreateInstance()
form = New HerculesWaitForm(_caption, _title)
Application.Run(form)
Application.DoEvents()
End Sub
Public Overloads Shared Sub Show(ByVal caption As String, ByVal title As String)
_caption = caption
_title = title
If form Is Nothing Then
_thread = New Thread(AddressOf CreateInstance)
_thread.IsBackground = True
_thread.Start()
End If
End Sub
Public Overloads Shared Sub SetCaption(ByVal caption As String)
If form IsNot Nothing Then
_caption = caption
form.SetFormCaption()
Else
Show(caption, "")
End If
End Sub
Public Overloads Shared Sub Close()
If form IsNot Nothing Then
form.CloseForm()
form = Nothing
End If
End Sub
Private Sub CloseForm()
If Me.InvokeRequired Then
Invoke(New MethodInvoker(AddressOf CloseForm))
Return
End If
Application.ExitThread()
End Sub
Private Sub SetFormCaption()
If Me.InvokeRequired Then
Invoke(New MethodInvoker(AddressOf SetFormCaption))
Return
End If
MyBase.SetCaption(_caption)
End Sub
End Class
答案 0 :(得分:2)
如果您将其称为:
Private Sub doSomethingLong()
HerculesWaitForm.Show("hi", "there")
Sleep(someAmount) 'Random long operation '
HerculesWaitForm.Close()
End Sub
如果您注意到,打开和关闭通话之间的时间很短,那么您可能遇到问题。这是因为对Show()
的调用启动了第二个线程,正在创建新的大力神对象,而正在执行您的操作。长时间操作立即开始,同时线程开始执行自我启动和运行的任务。
如果在线程完成初始化并完成Close()
对象的实例化之前调用form
,那么对Close()
的调用将找到form = Nothing
和它只会在没有做任何事情的情况下返回。
然后改变Show()
这样的代码:
Public Overloads Shared Sub Show(ByVal caption As String, ByVal title As String)
_caption = caption
_title = title
If form Is Nothing Then
_thread = New Thread(AddressOf CreateInstance)
_thread.SetApartmentState(ApartmentState.STA) 'should do this '
_thread.IsBackground = True
_thread.Start()
End If
While form Is Nothing ' add '
Thread.Sleep(1) ' this '
End While ' here '
End Sub
将强制Show()
方法阻止,直到工作线程创建了form
对象 - 这样可以确保不会简单地跳过将来Close
的所有调用(因为{{1} }})。不漂亮,但没有重构整个课程,它可能是最快的修复。
然而,这实际上是处理长时间操作的一种非常糟糕的方式。您正在创建一个新的UI线程来运行愚蠢的动画,同时阻止真正的UI线程执行耗时的操作,而不是将工作放入工作线程。除了是可怕的设计实践,这也有你的DevExpress插件形式将高于所有其他应用程序之上徘徊(因为它是一种应用程序本身的从这个类调用时)的作用,否认你的用户多任务的能力其他应用程序,因为您的应用程序正在窃取正面和中心,以显示它正在处理某些事情。
你真的应该使用ThreadPool或BackgroundWorker或其他类型的工作线程来代替复杂的操作。这使得您的主UI线程可以自由地提供长操作的状态更新,并避免上面的双UI线程混乱。
答案 1 :(得分:2)
您需要在启动线程之前调用_thread.SetApartmentState(ApartmentState.STA)。