2016-06-01 15 views
1

私はWPFを使用しており、メインスレッドはGUI(ウィザード)です。進捗バーWPFを持つbackgroundworkerの2つの問題WPF

ウィザードで[完了]をクリックすると、バックグラウンドワーカーで使用されているユーザープログレスバーを表示する2番目のスレッドが開きます。メインスレッドで

私がやって:私は1によって下記のとおり、私は、バックグラウンドワーカーでそれを使用currentStepという静的変数をインクリメント各createFiles方法で

MessageWithProgressBar progress = new MessageWithProgressBar(); 
progress.Show(); 
createFilesInA(); 
createFilesInB(); 
createFilesInC(); 
createFilesInD(); 
createFilesInE(); 
createFilesInF(); 
createFilesInG(); 
createFilesInH(); 
createFilesInI(); 
createFilesInJ(); 
createFilesInK(); 

を。バックグラウンドワーカーで

私がやって:

public partial class MessageWithProgressBar : Window 
{ 
    private BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    public MessageWithProgressBar() 
    { 
     InitializeComponent(); 
     backgroundWorker.WorkerReportsProgress = true; 
     backgroundWorker.ProgressChanged += ProgressChanged; 
     backgroundWorker.DoWork += DoWork; 
     backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; 
    } 

    private void DoWork(object sender, DoWorkEventArgs e) 
    { 
     Thread.Sleep(100); 
     int i = GeneralProperties.General.currentStep; 
     if (i > GeneralProperties.General.thresholdStep) 
     { 
      progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
             new DispatcherOperationCallback(delegate 
             { 
              progress.Value = 100; 
              title.Content = progress.Value.ToString(); 
              return null; 
             }), null); 
      return; 
     } 
     else 
     { 
      progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
             new DispatcherOperationCallback(delegate 
             { 
              progress.Value = (int)Math.Floor((decimal)(8 * i)); 
              progressLabel.Text = progress.Value.ToString(); 
              return null; 
             }), null); 
     } 
    } 

    private void ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
             new DispatcherOperationCallback(delegate 
             { 
              progress.Value = e.ProgressPercentage; 
              return null; 
             }), null); 
    } 

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
             new DispatcherOperationCallback(delegate 
             { 
              progress.Value = 100; 
              title.Content = progress.Value.ToString(); 
              return null; 
             }), null); 
     WindowMsgGenDB msg = new WindowMsgGenDB(); 
     msg.Show(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     if (backgroundWorker.IsBusy == false) 
     { 
      backgroundWorker.RunWorkerAsync(); 
     } 
    } 
} 

currentStepと呼ばれるメインスレッド更新された変数と2番目のスレッドがメインスレッドの進捗状況を報告するためにそれを使用しました。

メインスレッドの操作は、数秒(多くて15秒)

私は2つの問題持って取ります。私はプログレスバーに表示

  1. をする場合にのみcurrentStep = 2(その後、進捗状況は16です)、進捗状況は100であり、すべてのステップが表示されません。

  2. 最初は進捗バーが停止しているようです。

(多分それはコールprogress.Show(に接続する)メインスレッドから?)

ありがとう!

+0

バインドを介してプログレスバーの値を設定しますか?または直接? @ –

+0

@直接ヌード。上記のコードを参照してください。 – Programmer

+0

ええええええええええええええええええええええええええええええとお願いします。 –

答えて

2

あなたのコードを理解する限り、あなたのバックグラウンドワーカーは何もしていません。進捗状況を一度に更新します。また

:フォームとバックグラウンドワーカーの間の通信にグローバル静的変数を使用して - あなたは私の意見では、それは間違って使用している、また痛い...

を。仕事(CreateFilesInA ... CreateFilesInK)は、バックグラウンドワーカーによって行われなければなりません。メインスレッドは実装した方法でブロックされるため、それ以外の場合は更新が表示されません。

このような何かを実装するための通常の方法は次のとおりです。

  1. 進行状況ウィンドウを作成し、DoWorkで何かをしてUI
  2. スタート背景ワーカーを無効にします。 DoWorkでは、CreateFilesInXYZメソッドを呼び出すたびに、ReportProgressを呼び出してUIを更新します。
  3. 進行状況ウィンドウでアップデートのものProgressChangedイベントが
  4. 隠す進行状況ウィンドウを発射し、バックグラウンドワーカーが

あなたはそれが決して非同期であります、それをやっている方法で行われているときにアプリケーションのUIを有効にするたびに。だから、実際には、あなたのコードは次のようになります。

public partial class MainWindow : Window 
{ 
    private BackgroundWorker backgroundWorker = new BackgroundWorker(); 
    private MessageWithProgressBar progressWindow; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     backgroundWorker.WorkerReportsProgress = true; 
     backgroundWorker.ProgressChanged += ProgressChanged; 
     backgroundWorker.DoWork += DoWork; 
     backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     progressWindow = new MessageWithProgressBar(); 
     progressWindow.Owner = this; 
     progressWindow.Show(); 

     backgroundWorker.RunWorkerAsync(); 
    } 


    private void DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = (BackgroundWorker)sender; 
     int numSteps = 11; 
     int currentStep = 0; 
     int progress = 0; 

     CreateFilesInA(); 
     currentStep += 1; 

     progress = (int)((float)currentStep/(float)numSteps * 100.0); 
     worker.ReportProgress(progress); 

     CreateFilesInB(); 
     currentStep += 1; 

     progress = (int)((float)currentStep/(float)numSteps * 100.0); 
     worker.ReportProgress(progress); 

     // All other steps here 
     ... 
    } 

    private void ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progressWindow.progress.Value = e.ProgressPercentage; 
    } 

    private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     progressWindow.Close(); 

     WindowMsgGenDB msg = new WindowMsgGenDB(); 
     msg.Show(); 
    } 
} 

は、上記のコードは、あなたのメインウィンドウに入ることに注意してください! MessageWithProgressWindowにはコードは含まれていません。たぶん、Window_Loadedイベントハンドラは、バックグラウンドワーカーを起動するのに適切な場所ではないかもしれませんが、画像を取得します。

+0

メインウィンドウでMessageWithProgressBarのctorを定義するにはどうすればよいですか?メソッドが型を返さなければならないというエラーが発生しました – Programmer

+0

私はその質問を本当に理解できません。 'MessageWithProgressBar'クラスは、デフォルトでパラメータのないコンストラクタを持っています。あなたはすでにあなたのコードでそれを呼び出しています。あなたの質問を関連コードで更新してください。 –

+0

@ThorstenDittmarそれは単純なタイプミスです、私は疑います。あなたの 'MainWindow'は、間違った名前のコンストラクタを持っています。彼はメインウィンドウ内のctorを定義し –

関連する問題