0

簡単なウィンドウフォームを作成しました(以下に貼り付けます)。これを使用して、時間がかかる複雑な操作を実行しているときに、ユーザーに待機ダイログを表示します。

を呼び出す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
4

2 に答える 2

2

これを次のように呼んでいる場合:

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

次に、お気づきのように、オープンコールとクローズコールの間の時間が短い場合、問題が発生する可能性があります。これは、操作の実行Show()に、の呼び出しが新しいherculesオブジェクトの作成で機能する2番目のスレッドを開始するためです。長い操作はすぐに開始され、同時にスレッドはそれ自体を起動して実行するタスクを開始します。

スレッドがそれ自体の初期化とオブジェクトClose()のインスタンス化を完了する前にへの呼び出しが来た場合、への呼び出しはそれを見つけ、何もせずに単に戻るでしょう。formClose()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 に答える