我正试图让一个程序发布一堆文本。用户输入文本,消息量以及必须传递的速度。程序繁忙时,按钮文本需要“停止”而不是“开始”。在您最初启动它之后按下按钮强制它停止时,文本将更改回“开始”,但是在传送给定数量的消息后程序停止时不会发生这种情况,即使代码已到位且不会产生错误。
我有一种感觉,这是因为文字由于某种原因没有更新。我试图用Invalidate()和Update()来刷新它,但这不起作用。如何解决这个问题?
以下是代码:
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
isEvil = true;
button1.Text = "Stop";
Thread t = new Thread(StartTyping);
t.Start(textBox1.Text);
}
else
{
isEvil = false;
button1.Text = "Start";
}
}
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
//////This does NOT work
//button1.Text = "Start";
//button1.Invalidate();
//button1.Update();
//button1.Refresh();
//Application.DoEvents();
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
}
答案 0 :(得分:2)
您有四个答案告诉您从UI线程更新UI内容,但没有一个解决您的代码中的逻辑流问题。
之所以没有发生这种情况,是因为当isEvil
为false
时,它只会在for-loop 中发生。 isEvil
何时设置为false
?只有当你点击“停止”,而不是其他地方。
如果您希望按钮在线程完成后返回“开始”,而不单击“停止”,则需要在循环之后添加代码来执行此操作,与值无关isEvil
:(撇开VoidMain的回答)
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
if (button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
if (button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
}
现在您有重复的代码,因此您可能希望将其拆分为单独的方法。
答案 1 :(得分:0)
您需要在UI线程上更新UI。
尝试一下名为 SynchronizationContext 的内容。 google时有很多例子。
如果您在 WPF 或 Silverlight 中,则可以使用调度程序。同样,如果您在Google或StackOverflow中搜索这些关键字,还有很多示例。
答案 2 :(得分:0)
您必须从UI线程更新控件。这就是你如何为winforms做的。
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
button1.Invoke(new Action(() => button1.Text = "Start"));
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
这将阻止button1获取其文本更新。如果您不希望阻止,请将Invoke
替换为BeginInvoke
答案 3 :(得分:0)
这样的事情(未经测试)应该工作:
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
if(button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
}
答案 4 :(得分:0)
最好的办法是使用BackgroundWorker。在这里添加一个简洁的例子有点太过于操作但有一个decent tutorial from O'Reilly