最直白的例子:
private void btnStart_Click(object sender, EventArgs e) { int i = 0; while (i < 60) { labelTime.Text = i.ToString(); Thread.Sleep(1000); } }
运行的时候窗口死在哪里似的,不能动。这是不对的,下面看两种对的方法:
第一种方法:Timer
System.Windows.Forms.Timer 用于以用户定义的事件间隔触发事件。 Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理。 它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。
使用此计时器时,请使用 Tick 事件执行轮询操作,或在指定的时间内显示启动画面。 每当 Enabled 属性设置为 true 且 Interval 属性大于 0 时,将引发 Tick 事件,引发的时间间隔基于 Interval 属性设置。
此类提供用于设置时间间隔以及启动和停止计时器的方法。
Windows 窗体 Timer 组件是单线程组件,精度限定为 55 毫秒。 如果您需要更高精度的多线程计时器,请使用 System.Timers 命名空间中的 Timer 类。
private void btnStart_Click(object sender, EventArgs e) { System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); timer.Interval = 1000; timer.Tick += new EventHandler(RefreshTime); timer.Enabled = true; timer.Start(); } private void RefreshTime(object sender, EventArgs e) { int n = int.Parse(labelTime.Text); if (n > 0) { labelTime.Text = (n - 1).ToString(); } else { ((System.Windows.Forms.Timer)sender).Stop(); } }
窗口开可以动,还会有反应。
第二种方法:Thread
有时候我们需要创建一个线程,在线程里做这件事情。刷新Label必须由窗体主线程来做,具体做法是在创建的线程里把一个委托交给主线程。
Thread threadScan;//线程 long num = 0L;//计数 private void btnScan_Click(object sender, EventArgs e) { num = 0L; threadScan = new Thread(new ThreadStart(ScanFile)); threadScan.Start(); } //线程触发的方法 private void ScanFile() { SetText st = new SetText(UpdateLabel); while (num < 10) { if (labelScan.InvokeRequired) { labelScan.Invoke(st, num.ToString());//交给主线程 } else { labelScan.Text = num.ToString(); } num++; Thread.Sleep(1000); } threadScan.Abort(); } //委托 public delegate void SetText(string text); //委托调用的方法 private void UpdateLabel(string str) { labelScan.Text = str; }
顺便写一个匿名委托的例子
private void ScanFile() { while (num < 10) { if (labelScan.InvokeRequired) { SetText st = delegate(string str) { labelScan.Text = str; }; labelScan.Invoke(st, num.ToString()); } else { labelScan.Text = num.ToString(); } num++; Thread.Sleep(1000); } threadScan.Abort(); }
不用方法,不用new,对象等于delegate(参数){实现}。
一边自学,一边总结,有不对的地方请不要吝啬拍砖