3

数年間の開発に投資したプロジェクトがあり、一部のプロセスが非常に長いため、現在、進行状況ウィンドウが必要です。3D CAD、高度なエンジニアリング、シミュレーション サードパーティ DLL、Web サービス、WCF サービスを扱っています。

現在、1 つの場所で開始して他の場所で終了できる汎用プロセス ウィンドウを追加しようとしています。それは言うまでもなく複雑ではありません。ウィンドウを開き、負荷の高いコードが完了するMyClass.Open(string Message)とウィンドウを非表示にする単純な静的クラス。MyClass.Close()重いコードがスレッドをブロックすることを除いて、これは完全に機能します。

このプロジェクトは一連のプロジェクトの組み合わせですが、この部分は 99% WPF であり、winforms のように動作しないため、WPF スレッドにはかなり慣れていません。winformsスレッドで、他のフォームを開くことがメインアプリの重い作業によってブロックされないように作成します。WPF では、コードをコピーして貼り付けると、フォームが凍結されます。

Thread と Background Worker を試しましたが成功しませんでした。次に、それが私のウィンドウの問題または静的クラスではないことを確認するために、重い作業関数の 1 つでウィンドウを手動で開いてみましForm.Show();Form.Close();が、フォームはまだ表示され、適切に閉じられますが、まだフリーズしています。それから私はそれを取り除き、Form.Close();作業が完了した直後に動き始めました。現在、メインスレッドがフルキャパシティで動作しているときに他のスレッドがフリーズするのは非常に奇妙です。代わりにラベル付きのフォームであることを除いて、その進行状況ウィンドウの実際の正確なコピーがwinformにあり、グリッドにラベル付きのWPFウィンドウがあります。

重い関数のスレッドを作成する正しい方法で実行しようとしましたが、コンパイラで 2,404 エラーが発生しました。何かがうまくいくかどうかを試すために少なくとも1週間の作業が必要であり、プロジェクト全体を変更するのは少なくとも1年半かかるので、これを完了するのに通常2〜3週間かかります。探しているか、それを終わらせるのに役立つかもしれない解決策。私は非常に汚れることができます。それが機能する限り。

どうもありがとうございます。

編集: @Baldrick は、スレッドに関する詳細を要求しました。

スレッドは非常にシンプルになりました。

public static class CWaitingMessage
{
    private static frmWaiting window = new frmWaiting();
    private static Thread t = null;
    private static string Message = "";

    public static void Open(string sMessage)
    {
        Message = sMessage;

        t = new Thread(new ThreadStart(RunForm));
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();
    }     

    private static void RunForm()
    {
        try
        {
            window = new frmWaiting();
            window.UpdateText(Message);
            window.Show();
            System.Windows.Threading.Dispatcher.Run();
        }
        catch
        {
            window.Close();
        }
    }

    public static void Close()
    {
        if (t != null)
        {
            t.Abort("Completed");
        }
    }      
}

System.Windows.Threading.Dispatcher.Run();代わりに使用するwhile (ShowForm) { }と、フォームは凍結されませんが、それによってスレッドが消えます。つまり、到達することはありませんf.Close();

編集#2:dispatcher.Runを使用してスレッドを中止することができましたが、今はもっと大きな問題があります。プログラムは停止しません。スレッドの開始、次にスレッド例外の特別なキャッチで中止を呼び出し、中止時にウィンドウ内のメソッドを呼び出して、開いている時間を節約し、フォームを閉じます。私はチェックし、ファイルが作成されているので、中止は機能しますが、 Dispatche.Run が居住しているスレッドで呼び出された場合、それは自分自身で生きているようです。今、私は決して実行を停止しないモンスターを作成しました。アプリを完全に閉じます。ビジュアル スタジオではまだ実行中と見なされます。

私はWPFでの解決策を忘れてしまい、winformフォームでそのメッセージを表示することに非常に近づいています。

編集#3:現在使用しているクラスを更新しました。古い例とバックグラウンドワーカーを確認しましたが、通常のフォームロードのみを行ってから、バックグラウンドワーカーを実行してループしました。フォームはメイン コードと同じスレッドにありましたが、これはバックグラウンド ワーカーが MTA であるため完全に正常であり、したがって UI スレッドをブロックします。UIの場合、STAであるスレッドが必要です。

テストするためにdispatcher.Invokeを呼び出すことができません。私はそれのためのアセンブリを見つけることができませんでした。私のコンパイラとインテリセンスはデフォルトでそれを好きではありません:)

4

2 に答える 2

3

非同期メソッドを作成するためのはるかに簡単な方法があるため、このThreadクラスは最近ではあまり使用されていません。たとえば、WPF で非同期メソッドを簡単に作成する方法の例については、MSDN のTaskクラスページを参照してください。

.NET 4.5 を使用している場合は、 newasyncおよびawaitキーワードを使用して、さらに簡単な非同期メソッドを使用することもできます。コード例を含むこの新しい機能の詳細な説明については、MSDNのawait (C# リファレンス)ページを参照してください。

そうは言っても、UI スレッドで UI を簡単に更新できる更新機能を実装するには、実際には を使用するのBackgroundWorkerが最善の方法かもしれません。完全な例については、MSDN のクラスページをProgressBarご覧ください。BackgroundWorker

特定のヘルプが必要な場合は、質問を編集して関連するコードを追加してください。

于 2013-10-25T12:07:21.287 に答える