0

I have created a simple window form(pasted below). Now I use this to display a wait dailog to the user when running a complex operation which consumes time.

Calling the HerculesWaitForm.Show("Some Title","Some Caption...) shows the form as usual but when calling HerculesWaitForm.Close still shows the form. What can I do to overcome the problem.

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
4

2 回答 2

2

如果您将其称为:

Private Sub doSomethingLong()
    HerculesWaitForm.Show("hi", "there")
    Sleep(someAmount)  'Random long operation '
    HerculesWaitForm.Close()
End Sub

然后,您可能会遇到问题,如您所指出的,如果打开和关闭通话之间的时间很短。这是因为在您执行操作时,调用会Show()启动第二个线程来创建新的 hercules 对象。长操作立即开始,同时线程开始启动并运行自己的任务。

如果在Close()线程完成自身初始化并完成form对象的实例化之前调用 to ,那么调用 toClose()将找到它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不会简单地跳过所有未来的调用(因为form is nothing)。不漂亮,但如果不重构整个类,它可能是最快的修复。

然而,这实际上是处理长时间操作的一种非常糟糕的方法。您不是将工作放入工作线程,而是创建一个新的 UI 线程来运行愚蠢的动画,同时阻止真正的 UI 线程执行耗时的操作。除了糟糕的设计实践之外,这还会导致您的 DevExpress 小部件表单将悬停在所有其他应用程序之上(因为从此类调用时它本身就是一种应用程序),从而使您的用户无法进行多任务处理其他应用程序,因为您的应用程序正在窃取前端和中心以表明它正在做某事。

您确实应该使用 ThreadPool 或 BackgroundWorker 或其他类型的工作线程来执行复杂的操作。这使您的主 UI 线程可以自由地提供长操作的状态更新,并避免上述双 UI 线程混乱。

于 2013-03-13T10:34:29.513 回答
2

您需要在启动线程之前调用 _thread.SetApartmentState(ApartmentState.STA)。

于 2013-03-13T13:20:25.477 回答