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