で更新しています。UIスレッド(テキストボックス)をC#
私は基本的にコマンドラインツールを "やる"ループで実行する自作のwinformsアプリケーションを構築しました。上記のものは数秒または数分で完了することがあります。通常、私はDataTableに座っている行ごとにツールを一度実行する必要があります。
私は、コマンドラインツールの出力をリダイレクトし、 "my"アプリケーションに表示する必要があります。私はテキストボックスを介してそうしようとしています。私は自分で修正することができないUIスレッドの更新に関する問題に取り組んでいます。
私のコマンドラインツールを実行するには、私はここからコードを借りてきました。ここで
How to parse command line output from c#?は私と同等です:私はcmd_DataReceivedの私のStringBuilderをインスタンス化するときtxtOuput.textを参照
private void btnImport_Click(object sender, EventArgs e)
{
txtOutput.Clear();
ImportWorkbooks(dtable);
}
public void ImportWorkbooks(DataTable dt)
{
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
cmdStartInfo.FileName = @"C:\Windows\System32\cmd.exe";
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = false;
Process cmdProcess = new Process();
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.OutputDataReceived += cmd_DataReceived;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
cmdProcess.BeginErrorReadLine();
//Login
cmdProcess.StandardInput.WriteLine(BuildLoginString(txtTabCmd.Text, txtImportUserName.Text, txtImportPassword.Text, txtImportToServer.Text));
foreach (DataRow dr in dt.Rows)
{
cmdProcess.StandardInput.WriteLine(CreateServerProjectsString(dr["Project"].ToString(), txtTabCmd.Text));
//Import Workbook
cmdProcess.StandardInput.WriteLine(BuildPublishString(txtTabCmd.Text, dr["Name"].ToString(), dr["UID"].ToString(),dr["Password"].ToString(), dr["Project"].ToString()));
}
cmdProcess.StandardInput.WriteLine("exit"); //Execute exit.
cmdProcess.EnableRaisingEvents = false;
cmdProcess.WaitForExit();
}
private void cmd_DataReceived(object sender, DataReceivedEventArgs e)
{
//MessageBox.Show("Output from other process");
try
{
// I want to update my textbox here, and then position the cursor
// at the bottom ala:
StringBuilder sb = new StringBuilder(txtOutput.Text);
sb.AppendLine(e.Data.ToString());
txtOutput.Text = sb.ToString();
this.txtOutput.SelectionStart = txtOutput.Text.Length;
this.txtOutput.ScrollToCaret();
}
catch (Exception ex)
{
Console.WriteLine("{0} Exception caught.", ex);
}
}
()きちんとアプリがハングアップする:私はある種のクロススレッドの問題を推測している。
txtOutput.Text = sb.ToString();
Cross-thread operation not valid: Control 'txtOutput' accessed from a thread other than the thread it was created on.
OK、驚いていない:私はStringBuilderの中txtOuput.textへの参照を削除し、デバッグを続行した場合
は、私はここで、クロススレッド違反を取得します。私は、Process.Start()の後に処理を実行した結果、別のスレッドでcmd_DataReceivedが実行されていると仮定しました。cmd_DataReceived()のtxtOuput.Textへの参照をすべて削除し、単にコマンドラインのテキストをダンプするとConsole.Write()経由でコンソールに出力すると、すべて正常に動作します。
delegate void SetTextCallback(string text);
// This thread is used to demonstrate both thread-safe and
// unsafe ways to call a Windows Forms control.
private Thread demoThread = null;
I:
だから、次の私は、私は私のクラスにデリゲートを追加して、スレッド
http://msdn.microsoft.com/en-us/library/ms171728.aspx内の情報を使用してUIスレッドで私のテキストボックスを更新するための標準的な技術を試してみるつもりですテキストボックスを更新するための手順を追加します。
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.txtOutput.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.txtOutput.Text = text;
}
}
私はスレッドセーフなものを呼び出して別のPROCを追加します。
private void ThreadProcSafe()
{
// this.SetText(sb3.ToString());
this.SetText("foo");
}
...そして最終的に私はこのようcmd_DataReceived以内にこの混乱を呼ぶ:私はこのテキストを実行すると、テキストボックスが更新され得ていない、doornailとしてそこに死んで座っている...
private void cmd_DataReceived(object sender, DataReceivedEventArgs e)
{
//MessageBox.Show("Output from other process");
try
{
sb3.AppendLine(e.Data.ToString());
//this.backgroundWorker2.RunWorkerAsync();
this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
Console.WriteLine(e.Data.ToString());
}
catch (Exception ex)
{
Console.WriteLine("{0} Exception caught.", ex);
}
}
。私のコンソールウィンドウは更新を続けます。ご覧のとおり、テキストボックスにツールからの実際の出力を表示するように設定すると、ちょっと単純化されましたが、喜びはありません。私のUIは死んでいる。
だから何ですか?私が間違っていることを理解できません。私はテキストボックスに結果を表示することに結婚していません - 私はアプリケーション内で何が起こっているのかを見ることができ、別のウィンドウをポップアップしないようにしたいと思うだけです。
多くのありがとうございます。
しかし、UIスレッドは 'cmdProcess.WaitForExit();'行によってブロックされているので、テキストボックスはまだ更新されません。 – Fischermaen
ありがとう、私はあなたの提案をFishermanとKooKizのものと組み合わせようとします。 –