別のクラスで実行されている他のスレッドからプログレスバーを更新しようとして立ち往生しています。私が何をしているのかを説明するために、私は絵が良くなると思います。 //ここのポイントでプログレスバーを更新したい:
私はデリゲートを使用してみましたが、ReportProgressを試してみましたが、基本的に最初の100件の結果でグーグルが報告したすべてのものを使用しようとしましたが成功しなかったと思います。私はまだWPFを学んでおり、これを進めるのはばかげた方法かもしれません。作業を完了するための迅速で汚い方法を探していますが、よりクリーンなアプリケーションのために何を再設計すべきかを自由に教えてください。
[〜#〜] edit [〜#〜]:より多くのコード。
ExecutorWindow.xaml.cs内:
public void RunExecutor()
{
// CREATE BACKGROUNDWORKER FOR EXECUTOR
execBackground.DoWork += new DoWorkEventHandler(execBackground_DoWork);
execBackground.RunWorkerCompleted += new RunWorkerCompletedEventHandler(execBackground_RunWorkerCompleted);
execBackground.ProgressChanged += new ProgressChangedEventHandler(execBackground_ProgressChanged);
execBackground.WorkerReportsProgress = true;
execBackground.WorkerSupportsCancellation = true;
// RUN BACKGROUNDWORKER
execBackground.RunWorkerAsync();
}
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run();
}
private void execBackground_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("RunWorkerCompleted execBackground");
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
// TESTING
private void updateProgressBar(int i)
{
ExecutorProgressBar.Value += i;
}
public delegate void callback_updateProgressBar(int i);
Executor.cs内:
public void Run()
{
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
// HERE ?
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
while (CurrentRunningThreads > 0) { }
logfile.Close();
MessageBox.Show("All Tasks finished");
}
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
string[] options = (string[])e.Argument;
string machine = options[0];
string script = options[1];
// UPDATE HERE PROGRESSBAR ?
RemoteProcess myRemoteProcess = new RemoteProcess(machine, script);
string output = myRemoteProcess.TrueExec();
// UPDATE HERE PROGRESSBAR ?
this.logfile.WriteLine(output);
}
private void backgroundWorkerRemoteProcess_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
CurrentRunningThreads--;
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//myExecWindow.ExecutorProgressBar.Value = e.ProgressPercentage; // TESTING
//ExecutorWindow.callback_updateProgressBar(1); // TESTING
}
編集2:わかりました!実際は単純ですが、私はあまりにも近くを探していたのでわかりません。
私のExecutorWindowクラスでは:
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run(sender);
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
そして私のエグゼキュータクラスでは:
private BackgroundWorker myExecutorWindow;
[...]
public void Run(object sender)
{
myExecutorWindow = sender as BackgroundWorker;
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
[...]
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
myBackgroundWorker.ReportProgress(1);
// PROCESSING MY STUFF HERE
myBackgroundWorker.ReportProgress(1);
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myExecutorWindow.ReportProgress(1);
}
ありがとうございました !
わかった!実際は単純ですが、私はあまりにも近くを探していたのでわかりません。
私のExecutorWindowクラスでは:
private void execBackground_DoWork(object sender, DoWorkEventArgs e)
{
myExecutor = new Executor(arg1, arg2);
myExecutor.Run(sender);
}
private void execBackground_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ExecutorProgressBar.Value += 1;
}
そして私のエグゼキュータクラスでは:
private BackgroundWorker myExecutorWindow;
[...]
public void Run(object sender)
{
myExecutorWindow = sender as BackgroundWorker;
string[] options = new string[2];
int i = 0;
while (LeftToRun > 0)
{
if (CurrentRunningThreads < MaxThreadsRunning)
{
BackgroundWorker myThread = new BackgroundWorker();
myThread.DoWork += new DoWorkEventHandler(backgroundWorkerRemoteProcess_DoWork);
myThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerRemoteProcess_RunWorkerCompleted);
myThread.ProgressChanged += new ProgressChangedEventHandler(backgroundWorkerRemoteProcess_ProgressChanged);
myThread.WorkerReportsProgress = true;
myThread.WorkerSupportsCancellation = true;
myThread.RunWorkerAsync(new string[2] {opt1, opt2});
CurrentRunningThreads++;
i++;
LeftToRun--;
}
}
[...]
private void backgroundWorkerRemoteProcess_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker myBackgroundWorker = sender as BackgroundWorker;
myBackgroundWorker.ReportProgress(1);
// PROCESSING MY STUFF HERE
myBackgroundWorker.ReportProgress(1);
}
private void backgroundWorkerRemoteProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myExecutorWindow.ReportProgress(1);
}
この非常に基本的なサンプルを使用して、UIスレッドで任意のメソッドを実行できます
this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
{
this.progressBar.Value= 20; // Do all the ui thread updates here
}));
Dispatcher.Invoke(...)内でコマンドを実行すると、実際には任意のワーカースレッドからUIを操作できます。そうしないと、例外が発生します。
バックグラウンドスレッドとメイン(UI)スレッドの更新を最終的に制御する必要がある場合は、次の素晴らしいチュートリアルをご覧ください。 http://blog.decarufel.net/2009/03/good-practice -to-use-dispatcher-in-wpf.html
Dispatcher.Invokeメソッドを使用できるはずです
例えば.
Dispatcher.Invoke(
new System.Action(() => myProgressBar.Value = newValue)
);
コードのブロックを実行するスレッドを作成し、呼び出しをメインスレッドに戻してコントロールのプロパティを変更する、非常に簡単なソリューションを見つけました。 .NET 4.5でそのまま動作し、ディスパッチャでのラムダ呼び出しは、以前のバージョンの.NETで動作するように適合させることができます。主な利点は、非常に基本的なコードのクイックスレッドが必要な場合に、非常にシンプルで完璧なことです。
したがって、スコープ内のダイアログのどこかにプログレスバーがあると仮定して、次のようにします。
progBar.Minimum = 0;
progBar.Maximum = theMaxValue;
progBar.Value = 0;
Dispatcher disp = Dispatcher.CurrentDispatcher;
new Thread(() => {
// Code executing in other thread
while (progBar.Value < theMaxValue)
{
// Your application logic here
// Invoke Main Thread UI updates
disp.Invoke(
() =>
{
progBar.Value++;
}
);
}
}).Start();
また、WindowsBase.dllへの参照があることを確認する必要があります
スレッドの開始時に実行されるコードのより再利用可能なスニペットが必要な場合は、デリゲートとしてメソッドを使用できますが、インラインラムダは単純なタスクにとって非常に簡単であり、バックグラウンドワーカーのアプローチのようにイベントを処理する必要はありません。