激活或停用按钮取决于另一个按钮

本文关键字:按钮 取决于 另一个 激活 | 更新日期: 2023-09-27 18:04:21

我是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;
        }
    }
}

这里的问题是,当我点击一个按钮,它不允许我点击另一个按钮。我使用了一个全局变量来检测按下了哪个按钮。但这行不通。我该怎么做呢?

激活或停用按钮取决于另一个按钮

你在UI线程上做所有这些,所以你阻塞了它。您需要让另一个线程执行实际的计数,并通过使用Control.Invoke将标签更改委托给主线程,以便主线程有时间运行消息泵。您可以使用内置的BackgroundWorker或简单地使用ThreadPoolTaskFactory创建一个线程。

我写了一个简短的例子来说明如何用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;
                        }
                    }
                });
    }

您这里遇到的问题是线程问题。

当你有winforms时,主线程的工作是显示和使界面交互,并执行你给它的任何任务。

在您的代码中,您开始倒计时。但是在那里,使界面工作的同一个线程现在正忙于减少你的值,所以它不会更新界面或响应按钮,直到它准备好了。

你想要的是一个帮助线程来为你做倒计时(或者老实说,启动一个TIMER代替)。否则,在你完成循环之前,界面将是非交互式的。

定时器是最简单的方法。

http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx