2011-11-19 7 views
4

私はUIとして機能し、外部exeを実行するC#フォームアプリケーションを持っています。外部のexeが実行を終了するまで、プログレスバーを増分したい。だから私は、次のコードを持っている:スレッドが終了するのを待つ間にプログレスバーが進まない

// create thread and Start external process 

Thread MyNewThread = new Thread(new ThreadStart(startmodule)); 
MyNewThread.Start(); 

      do 
      { 
       if (progressBar1.Value < 100) 
       { 
        progressBar1.Value++; 
       } 
      } while (MyNewThread.IsAlive); 

      label5.Text = "Status: Done"; 

// startmodule() 
void startmodule() 
    { 
     ProcessObj = new Process(); 
     ProcessObj.StartInfo.FileName = ApplicationPath; 
     ProcessObj.StartInfo.Arguments = ApplicationArguments; 
     ProcessObj.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 
     ProcessObj.Start(); 
    } 

は、その代わりに、瞬時にバーをいっぱいにし、「完了」のメッセージが、外部exeファイル(APPPATH)はまだバックグラウンドで実行されますと表示されます。

いくつかのアイデアを投稿してください。私は何が間違っているのか分からない。あなたの時間をありがとう。

答えて

4

これを行うことはできません。プロセスの所要時間を推測することはできません。 ProgressBar.StyleプロパティをMarqueeに設定します。プロセスを開始するときにVisibleプロパティをtrueに設定します。 Process.Exitedイベントを使用してfalseに戻します。このように:

public partial class Form1 : Form { 
    public Form1() { 
     InitializeComponent(); 
     progressBar1.Style = ProgressBarStyle.Marquee; 
     progressBar1.Visible = false; 
    } 

    private void ButtonRunProcess_Click(object sender, EventArgs e) { 
     var ProcessObj = new Process(); 
     ProcessObj.SynchronizingObject = this; 
     ProcessObj.EnableRaisingEvents = true; 
     ProcessObj.Exited += new EventHandler(ProcessObj_Exited); 
     ProcessObj.StartInfo.FileName = @"c:\windows\notepad.exe"; 
     // etc... 
     ProcessObj.Start(); 
     progressBar1.Visible = true; 
    } 

    void ProcessObj_Exited(object sender, EventArgs e) { 
     progressBar1.Visible = false; 
    } 
} 
4

ループは非常に速く実行されており、タスクが実際に完了する前に100%に達しています。ループがチェックされている状態(スレッドが生きている)は、タスクが完了するまで真となりますが、ループによって進行状況バーが途中でいっぱいになってしまいます。

+1

ティムズはここで徘徊しています。あなたのループには実際の進歩に結びつくものは何もないので、ループはできるだけ早く実行されるので、なぜ100%に瞬時にジャンプするように見えますか? BackgroundWorkerは、ReportProgressメソッドをサポートしているため、主スレッドに非同期に進行状況を通知できるため、BackgroundWorkerを使用することができます。そして実際、あなたのバックグラウンドスレッドは、おそらくそれがどれだけ成し遂げられたかを知るために装備されています。 –

+0

今、私はあなたが「あなたのスタート・モジュール内のプログレス・バーを増やすことができるかもしれません」という意味を理解するのに苦労しています。 –

+0

闘争はもう終了しません。 – Tim

0

まず、何が起こっているのかについての@Timの回答が正しいです。

外部アプリケーションを制御できる場合は、メインアプリケーションと通信して現在の状態を通知し、これらのメッセージに従って進行状況バーを更新します。

実行できない場合は、実行時間を見積もり、実行時間に応じて進捗を設定してください。これは、同じタスクに対して常に同じ時刻に実行される場合に有効です。

+0

まあ問題は、私がそれを制御することができ、時間が変わるので、通信は不可能です。最後の手段はマーキースタイルです。しかし、悪いバックグラウンドワーカーを試してみてください。良い例があれば投稿してください。皆さん、ありがとうございました。 – sparky

+0

修正:できません – sparky

1

プログレスバーを実行するには、長時間実行されているタスクの進行状況を定量化できる必要があります。コード内にこれを数量化しようとするものは何もありません。

このプログレスバーをうまく機能させるには、2つのプロセス間の通信が必要です。言い換えれば、外部プロセスは親アプリケーションにメッセージを送って、親アプリケーションに進捗の指標を知らせる必要があります。さて、達成するのが難しいかもしれないので、marquee styleプログレスバーがより適切かもしれません。

0

バックグラウンドワーカースレッドは、この種のもののために設計されました。 何かを処理しているときに発砲するイベントがあります。処理して進行状況バーを更新します。あなたが進歩の尺度を持っていないように見える他の人が指摘したように、ちょうど時間が経過しているので、あなたが進歩を示しているのではないでしょうか? 100%にならないか、操作が完了する前に100%になるか、さらにはサイクルラウンドになるかのように、UIの男の子を怒らせるあらゆる種類の問題が発生します。

スレッドから何らかの進捗状況を示すことができます。たとえば、X項目をループしている場合、Xの10%ごとにprogressイベントが発生します。バックグラウンドワーカースレッドを使用します。 プログレスバーを使用できない場合は、スレッドをオフにしてアニメーションコントロールを表示させます。スレッドが終了すると、再びアニメーションが非表示になります。アニメーションの内容と方法は、あなたとあなたのUIボーイズまでです。

1

最後に、上記のようにバックグラウンドワーカーをテストするための「フリー」時間があります。私はそれが最高の解決策であり、UIをフリーズしないと言うことができます。実装例は次のとおりです。

preparemodule() 
{ 
    ProcessObj = new Process(); 
    ProcessObj.StartInfo.FileName = ApplicationPath; 
    ProcessObj.StartInfo.Arguments = ApplicationArguments; 
} 

void run_Click(object sender, EventArgs e) 
{ 
    preparemodule(); 
    backgroundWorker1.RunWorkerAsync(ProcessObj); 
} 

void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int i=0; 

    ProcessObj.Start(); 

    while (checkifexists("notepad", 0) == true) 
    { 
    i++; 
    label5.Text = "Status: notepad running... " + progressBar1.Value.ToString() + "%"; 
    Thread.Sleep(3000); 
    backgroundWorker1.ReportProgress(i); 

    if ((backgroundWorker1.CancellationPending == true)) 
    { 
     e.Cancel = true; 
    } 
    } 
} 

void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     if (e.ProgressPercentage <= 100) 
     { 
      progressBar1.Value = e.ProgressPercentage; 
     } 
    } 

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 

     label5.Text = "Status: Done"; 
    } 

void cancel_Click(object sender, EventArgs e) 
    {  
     backgroundWorker1.CancelAsync(); 
    } 

ご覧のとおり、キャンセルすることもできます。メモ帳が動作しているかどうかをチェックすることで、プログレスバーをインクリメントすることができます。あなたのコードのどこかでbgWorkerの "reportsprogress"と "supportscancellation"プロパティを有効にすることを忘れないでください。私はそれが誰かを助けることを望む。

関連する問題