文本框只在其他线程完成后更新
本文关键字:更新 线程 其他 文本 | 更新日期: 2023-09-27 18:19:22
几天来,我一直在试图弄清楚如何使用使控制台更新文本框作为其执行。我得出的结论是,线程对于同时运行表单和控制台进程是绝对必要的。进程本身是独立的程序,所以我使用标准输出来获取信息,如果我不需要它来更新文本框,因为它的工作,这将是伟大的,但问题是,它只在执行进程后更新,虽然我,事实上,使用多线程。
是为运行进程和处理输出的函数制作委托的开始,以及我用于在线程和锁之间交换信息的字符串:
private static readonly object _locker = new object();
volatile string exchange = "";
delegate void CallDelegate(string filename);
下面是函数本身:
public void CallConsole(string filename)
{
Thread.CurrentThread.Name = "ProccessThread";
Thread.CurrentThread.IsBackground = false;
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.FileName = filename;
if (checkBox1.Checked)
p.StartInfo.CreateNoWindow = true;
string output;
p.Start();
while (!p.HasExited)
{
lock (_locker)
{
output = p.StandardError.ReadToEnd();
if (output.Length != 0)
{
exchange = output;
Thread.Sleep(100);
MessageBox.Show(output);
}
output = p.StandardOutput.ReadToEnd();
exchange = output;
System.Threading.Thread.Sleep(100);
}
}
}
下面是button_click
之后程序的执行 private void button1_Click_1(object sender, EventArgs e)
{
textBox2.Text = "";
//Thread.CurrentThread.Name = "Main";
CallDelegate call = new CallDelegate (CallConsole);
IAsyncResult tag = call.BeginInvoke(textBox1.Text, null, null);
button1.IsAccessible = false;
while (!tag.IsCompleted)
{
string temp = "";
lock (_locker)
{
Thread.Sleep(50);
if (exchange.Length != 0)
{
temp = exchange;
exchange = "";
}
}
if (temp.Length != 0)
textBox2.Text = textBox2.Text + temp;
}
call.EndInvoke(tag);
button1.IsAccessible = true;
}
注意:Textbox1为文件路径Textbox2是只读多行文本框
有没有人知道为什么只有在CallConsole完成后才会更新?
一般问题:你在button1_Click_1
内循环,有效地阻塞了UI线程。这可以防止其他事件被处理——包括重绘等。
你不应该那样做;相反,如果你想轮询一些东西,设置一个计时器来进行轮询,允许UI在"空闲"时间处理事件。
更直接的问题:您正在从未完成的进程调用读取器上的ReadToEnd
。这将(我相信)阻碍,直到进程完成。(在读完之前,读者并没有所谓的"结尾"。)这意味着你有一个线程持有锁并阻塞直到进程完成-然后你试图在UI线程中获取该锁。
我还建议使整个事情不那么依赖于轮询开始-查看Process
类上的事件,并尝试处理这些而不是在单独的线程中阻塞。当其中一个事件发生时,您可以发送回UI线程(使用Control.Invoke
)来更新UI…然后没有需要轮询