我试图使用线程,并防止程序冻结,而线程是繁忙的。它应该显示进步(0/1的书写),而不只是显示完成后的结果,同时冻结表单。
在当前的程序中,我试图写到一个文本框,实际上看到的是不断的进展,并且表单不会受到其他线程的任务的影响。
现在,我可以使用invoke写入带有线程的textbox,但它只显示结果(当线程繁忙时表单冻结),表单冻结。
表格图像:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace MultiThreading
{
public partial class MultiThreading : Form
{
public MultiThreading()
{
InitializeComponent();
}
Thread writeOne, writeTwo;
private void writeText(TextBox textBox, string text)
{
if (textBox.InvokeRequired)
{
textBox.BeginInvoke((MethodInvoker)delegate()
{
for (int i = 0; i < 500; i++)
{
textBox.Text += text;
}
});
}
else
{
for (int i = 0; i < 500; i++)
{
textBox.Text += text;
}
}
}
private void btnWrite1_Click(object sender, EventArgs e)
{
writeOne = new Thread(() => writeText(txtOutput1, "0"));
writeOne.Start();
}
private void btnWrite2_Click(object sender, EventArgs e)
{
writeTwo = new Thread(() => writeText(txtOutput2, "1"));
writeTwo.Start();
}
private void btnClear1_Click(object sender, EventArgs e)
{
txtOutput1.Clear();
}
private void btnClear2_Click(object sender, EventArgs e)
{
txtOutput2.Clear();
}
private void btnWriteBoth_Click(object sender, EventArgs e)
{
writeOne = new Thread(() => writeText(txtOutput1, "0"));
writeTwo = new Thread(() => writeText(txtOutput2, "1"));
writeOne.Start();
writeTwo.Start();
}
private void btnClearBoth_Click(object sender, EventArgs e)
{
txtOutput1.Clear();
txtOutput2.Clear();
}
}
}
编辑:
顺便说一句,我对多线程很陌生,我只是尝试编写一个小程序来理解实现这一目的的最佳方法。
我知道我以前的调用并没有提供真正的帮助,因为我仍然没有给表单一个更新的机会,所以它已经实现了。
好的,所以像这样运行一个线程,但是仍然一起运行多个线程,直到线程完成后才会更新表单。
我添加了一个thread.sleep(),以便在编写时可以尝试并清除,以查看是否仍然可以使用该表单。
当写到一个文本框时,我仍然可以在写的时候清除屏幕。
但是一旦我使用了2个线程,在线程完成并给出输出之前,我就不能再使用表单了。
private void writeText(TextBox textBox, string text)
{
for (int i = 0; i < 500; i++)
{
Invoke(new MethodInvoker(() =>
{
textBox.Text += text;
Thread.Sleep(2);
}));
}
}
(如果我在这一点上完全错了-我不介意阅读一些例子/线程,除了一个后台工作人员之外,我仍在努力寻找最好的方法。)
编辑2:
我减少了写的数量,减少了调用的次数,但是增加了延迟,产生了与常量写入相同的效果,只是减少了负载。
private void writeText(TextBox textBox, string text)
{
for (int i = 0; i < 500; i++)
{
Invoke(new MethodInvoker(() =>
{
textBox.Text += text;
Thread.Sleep(2);
}));
}
}
编辑3:
Sumeet的示例使用
Application.DoEvents();
(注意s,.DoEvent不工作,可能是:P),同时写入多个字符串&让它们显示进度,而不仅仅是结果。
因此,代码再次更新:)
*使用一个新按钮创建5个线程,将随机数写入两个文本框
private void writeText(TextBox textBox, string text)
{
for (int i = 0; i < 57; i++)
{
Invoke(new MethodInvoker(() =>
{
textBox.Text += text;
Thread.Sleep(5);
Application.DoEvents();
}));
}
}
private void btnNewThread_Click(object sender, EventArgs e)
{
Random random = new Random();
int[] randomNumber = new int[5];
for (int i = 0; i < 5; i++)
{
randomNumber[i] = random.Next(2, 9);
new Thread(() => writeText(txtOutput1, randomNumber[i-1].ToString())).Start();
new Thread(() => writeText(txtOutput2, randomNumber[i-1].ToString())).Start();
}
}
发布于 2013-01-28 11:40:47
这个解决方案有效!已经检查过了。
问题是,您一直告诉UI线程更改文本,但从不让它有时间显示更新的文本。若要使UI显示已更改的文本,请添加如下所示的Application.DoEvents行:
textBox.Text += text;
Application.DoEvents();
附注::删除If / else循环的Else块,它是多余的,而且正如其他人所指出的,创建这2个线程没有任何用处,因为他们所做的只是将消息发布在UI线程本身上。
发布于 2013-01-28 11:22:39
您仍在执行单线程任务,如果需要,只需在UI线程上重新启动它。
for (int i = 0; i < 500; i++){
string text = ""+i;
textBox.BeginInvoke((MethodInvoker)delegate()
{
textBox.Text += text;
});
}
发布于 2013-01-28 11:25:48
问题是您正在启动一个新线程,然后这个新线程除了为UI线程添加一个要处理大量工作的新任务之外,什么也不做。为了保持表单响应性,您需要有时间让UI线程什么也不做,或者至少不要花费大量的时间执行任何一项任务。
为了保持表单响应性,我们需要大量的小BeginInvoke
(或Invoke
)调用。
private void writeText(TextBox textBox, string text)
{
for (int i = 0; i < 500; i++)
{
Invoke(new MethodInvoker(() =>
{
textBox.Text += text;
}));
}
}
通过调用大量的小调用,它允许在操作过程中处理诸如画图事件、鼠标移动/单击事件等事件。还请注意,我删除了InvokeRequired
调用。我们知道这个方法将从一个非UI线程中调用,所以不需要它。
https://stackoverflow.com/questions/14569482
复制