我是C#的新手。我有两个button
和两个label
。我想要的是,当我点击button1
时,开始计数并显示在label1
中。当我按button2
时,它会在button1
下继续计数,开始在button2
下计数,并显示在label2中。这是我的代码
bool testt = true;
int i = 0;
int j = 0;
private void button1_Click(object sender, EventArgs e)
{
while (testt)
{
label1.Text = i.ToString();
i++;
System.Threading.Thread.Sleep(50);
if (i > 5000)
{
i = 0;
}
}
}
private void button2_Click(object sender, EventArgs e)
{
testt = false;
while (!testt)
{
label2.Text = j.ToString();
j++;
System.Threading.Thread.Sleep(50);
if (j > 5000)
{
i = 0;
}
}
}
这里的问题是当我点击一个按钮时,它不允许我点击另一个按钮。我使用全局变量来检测按下了哪个按钮。但它不起作用。我怎样才能做到这一点?
答案 0 :(得分:2)
你正在UI线程上做这一切,所以你阻止了它。您需要让另一个线程执行实际计数,并使用Control.Invoke
将标签更改为主线程,以便主线程有时间运行消息泵。您可以使用内置BackgroundWorker
或只使用ThreadPool
或TaskFactory
创建一个帖子。
我写了一个简短的例子,说明如何使用LINQ和ThreadPool实现这一点,它不是设计方面的最佳方法,但它可以为您提供开发适当解决方案的起点
semaphore = true;
int i = 0;
int j = 0;
private void button1_Click(object sender, EventArgs e)
{
semaphore = true;
ExecuteAsync(()=>
{
while (semaphore)
{
//Dispatch a call to the UI thread to change the label
Invoke((MethodInvoker)(() => ChangeLabel(label1, i.ToString())));
i++;
Thread.Sleep(50);
if (i > 5000)
{
i = 0;
}
}
});
}
//Executes a function on a ThreadPool thread
private void ExecuteAsync(Action action)
{
ThreadPool.QueueUserWorkItem(
obj => action());
}
private void ChangeLabel(Label label, string labelText)
{
label.Text = labelText;
}
private void button2_Click(object sender, EventArgs e)
{
semaphore = false;
ExecuteAsync(() =>
{
while (!semaphore)
{
//Dispatch a call to the UI thread to change the label
Invoke((MethodInvoker)(() => ChangeLabel(label2, j.ToString())));
j++;
Thread.Sleep(50);
if (j > 5000)
{
i = 0;
}
}
});
}
答案 1 :(得分:0)
您遇到的问题是线程问题。
当你有winforms时,主线程的作用是显示和使界面交互并执行你给它的任何任务。
在您的代码中,您开始倒计时。但是在那里,使界面工作的同一个线程现在正在忙着降低你的价值,因此在它准备就绪之前它不会更新界面或响应按钮。
你想要的是一个辅助线程为你做倒计时(或者老实说,启动一个TIMER)。否则,在您完成该循环之前,接口将是非交互式的。
计时器是最简单的方法。
http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx