Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/332.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 而循环不';更改布尔值后不能停止_C#_Winforms - Fatal编程技术网

C# 而循环不';更改布尔值后不能停止

C# 而循环不';更改布尔值后不能停止,c#,winforms,C#,Winforms,我正在使用windows窗体应用程序进行一个小的实验项目,在单击按钮后,我遇到了while循环的问题。单击按钮2后,布尔值b应更改为false,循环应停止,但不会停止 namespace Spalvos { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Boolean b;

我正在使用windows窗体应用程序进行一个小的实验项目,在单击按钮后,我遇到了while循环的问题。单击按钮2后,布尔值
b
应更改为false,循环应停止,但不会停止

namespace Spalvos
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Boolean b;
        private void button1_Click(object sender, EventArgs e)
        {
            b = true;
            while (b == true) {
                Random rnd = new Random();
                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);
                Application.DoEvents();
                System.Threading.Thread.Sleep(200);              
            }
        }

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

你的代码可以工作,但有点不稳定;来自按钮2的事件有时会丢失或延迟,可能是因为您将对
Sleep()
DoEvents
的调用混合在一起的方式造成的,并且非常不鼓励使用DoEvents,并且由于引入了
async
wait
而过时。另外,你应该只初始化一次你的
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;
    }
}
然而,这种解决方案也有它的问题。例如,想象一下,如果你点击按钮1两次会发生什么。可能不是我们想要的

我建议您将更改颜色的逻辑移到a,并使用
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);
}

这不是简单得多吗?

在代码中,您正在调用UI线程上的Thread.Sleep方法。这将导致阻塞UI。您可以通过扩展线程中的毫秒值来检查它。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;
        }
    }
}

我在上创建了示例。

不使用
DoEvents
的可能副本。这是VB时代的宿醉。如果您想在“后台”中执行某些操作,请启动一个线程或使用计时器。或者使用一个副本。您可以将您的代码以正确的格式放置吗?您不应该像那样在循环中初始化
rnd
,因为它使用系统时钟创建默认种子值。相反,您应该在类范围内声明它,并初始化它一次,以获得最佳的随机结果。感谢您的帮助。
random rnd=new random()不应位于循环内。