1

バックグラウンドワーカーが時間のかかる作業をしている間に、プログレスバーを表示するロードウィンドウを作成しようとしています。残念ながら、このロード ウィンドウは部分的にしかロードされず、バックグラウンド作業が完了するまでフリーズします。ロード ウィンドウがバックグラウンド プロセスと競合しないようにするにはどうすればよいですか?

視覚的な例: http://i.imgur.com/1jQszPt.png


        lw = new LoadWindow();
        lw.Show();            

        worker.DoWork += delegate(object s, DoWorkEventArgs args)
        {
            /*Program-specific code*/

            string theDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); /* get the folder location of the exe */
            string filePath = theDirectory + "\\export.xml";
            if (!File.Exists(filePath))
            {
                FileStream f = File.Create(filePath);
                f.Close();
            }

            FileStream fileStream = File.Open(filePath, FileMode.Open);
            fileStream.SetLength(0);
            fileStream.Close();

            FileStream fsWrite = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.None);
            StreamWriter sw = new StreamWriter(fsWrite);

            Dispatcher.Invoke(new Action(delegate() { 

                /*Program-specific code*/                    

                System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe", "/C svn log " + FolderPath.Text + " -v --xml");
                startInfo.CreateNoWindow = true;
                startInfo.RedirectStandardOutput = true;
                startInfo.UseShellExecute = false;
                using (System.Diagnostics.Process process = Process.Start(startInfo))
                {

                    using (StreamReader reader = process.StandardOutput)
                    {
                        string outStr = reader.ReadToEnd();
                        sw.Write(outStr);
                        sw.Close();
                        fsWrite.Close();
                        reader.Close();
                        process.WaitForExit();
                    }
                }
                TicketIDChanged(sender, new TextChangedEventArgs(e.RoutedEvent, new UndoAction()));
            }), DispatcherPriority.Background);             
        };

        worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
        {
            lw.Hide();
        };

        worker.RunWorkerAsync();
4

4 に答える 4

1

Dispatcher.Invoke()GUI スレッドで大量のコード (StartProcess から WaitForExit まで) を実行するために使用しています。はい、ブロックします。

Invoke の理由がわかりません。プロセスの実行は、 での実行に適していDoWork()ます。

同期が必要なTicketIDChanged()のは最後の部分だけです。それを行うDispatcher.Invoke()か、Completed イベントに移動します。

于 2013-07-15T21:24:32.340 に答える
1

を使用Dispatcher.Invoke()することで、デリゲート内のすべての作業を UI スレッドに委任します。これが時間のかかる操作である場合、ここで行き詰まります。

Dispatcher.Invoke()UI 状態の更新のみに使用してみてください。これに簡単にアクセスできない場合は、コードをリファクタリングして、複数の呼び出しを追加してみてください。

このメソッドを設定worker.WorkerReportsProgress = trueして使用しworker.ReportProgress(int percent, object args)て、ロード画面の簡単な進行状況バーを更新することもできます。その後、ディスパッチは BackgroundWorker によって処理されます。

TickedIDChangedたとえば、 - メソッドのみを呼び出すようにしてください。

于 2013-07-15T21:20:37.893 に答える
0

.NET 4.0 リリースでは、並列およびタスク ベースの非同期操作を実行するための API を提供する Task Parallel Library (TPL) を取得しました。TPL は、それぞれ非同期プログラミングと並列操作を実行するために使用された Task や Parallel などのクラスを提供します。C# 5.0 を使用した .NET 4.5 では、非同期メソッドを表す async キーワードと await キーワードを取得しました。WPF では、Task クラスを利用して、レスポンシブでインタラクティブなアプリケーションを作成できます。

于 2016-03-26T18:31:46.700 に答える