布尔值更改后,while循环不会停止

时间:2018-08-16 15:50:35

标签: c# winforms

我正在使用Windows窗体应用程序处理一个小型实验项目,单击按钮后,while循环出现问题。单击button2后,应将布尔值 var1 var2 var3 var4 var5 var6 var1 -1 0 0 0 0 0 var2 0 -1 0 0 0 0 var3 0 0 -1 0 0 0 var4 0 0 0 -1 0 0 var5 0 0 0 0 -1 0 更改为false,并且循环应停止,但不是。

b

2 个答案:

答案 0 :(得分:3)

您的代码可以使用,但是有点不完整; Button2中的事件有时会丢失或延迟,这可能是由于您将对Sleep()DoEvents的调用混合在一起的原因,因此强烈建议不要使用DoEvents,并会因引入async而废止和await。另外,您一次只能初始化Random(除非您做的事情确实很奇怪)。

如果使点击处理程序异步,则可以得到更好,更现代的解决方案,例如:

    private volatile Boolean b;

    private async void button1_Click(object sender, EventArgs e)
    {
        Random rnd = new Random();

        b = true;
        while (b)
        {
            int r = rnd.Next(0, 254);
            int n = rnd.Next(0, 254);
            int d = rnd.Next(0, 254);

            this.BackColor = Color.FromArgb(r, n, d);
            await Task.Delay(200);
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        b = false;
    }
}

但是,此解决方案也有其问题。想象一下,例如,如果单击两次Button1会发生什么。可能不是预期的。

我建议您将更改颜色的逻辑更改为timer control,并使用Button1事件处理程序启用它,并使用Button2事件处理程序禁用它。

public Form1()
{
    InitializeComponent();
    this.timer1.Interval = 200;
}

private Random rnd = new Random();

private void button1_Click(object sender, EventArgs e)
{
    this.timer1.Enabled = true;
}

private void button2_Click(object sender, EventArgs e)
{
    this.timer1.Enabled = false;
}

private void timer1_Tick(object sender, EventArgs e)
{
    int r = rnd.Next(0, 254);
    int n = rnd.Next(0, 254);
    int d = rnd.Next(0, 254);

    this.BackColor = Color.FromArgb(r, n, d);
}

不是那么简单吗?

答案 1 :(得分:0)

在您的代码中,您正在UI线程上调用 Thread.Sleep 方法。这将导致UI阻塞。您可以通过扩展 Thread.Sleep 中的毫秒值来检查它。

要使UI响应,请使用hack Application.DoEvents()。它将停止所有其他线程并调用所有正在等待的方法(在此示例中,该方法被循环阻止)。在运行该应用程序后,如果没有它,您的表单将被冻结,并且您将无法单击按钮或移动窗口。

这不是编写代码的正确方法。应用程序应该在后台执行最耗时的工作,并且只能切换较短的时间以在UI上执行操作。

好的方法是在后台循环时开始,在后台计算颜色,并在需要时使用委托切换到UI。

delegate void ChangeColorDelegate(Color c);
public partial class Form1 : Form
{
    Thread thread;
    Boolean b;
    Random Random;

    public Form1()
    {
        InitializeComponent();
        thread = new Thread(ChangeColorBackground);
        thread.Start();
        Random = new Random();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        b = true;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        b = false;
    }

    private void ChangeColorBackground()
    {
        while (true)
        {
            if (b == true)
            {
                int r = Random.Next(0, 254);
                int n = Random.Next(0, 254);
                int d = Random.Next(0, 254);
                Color c = Color.FromArgb(r, n, d);
                ChangeColorThreadSafe(c);
            }
            System.Threading.Thread.Sleep(100);
        }
    }

    private void ChangeColorThreadSafe(Color c)
    {
        if (button1.InvokeRequired)
        {
            ChangeColorDelegate delgate = new ChangeColorDelegate(ChangeColorThreadSafe);
            button1.Invoke(delgate, new object[] { c });
        }
        else
        {
            this.BackColor = c;
        }
    }
}

我在github上创建了示例。