winform窗口不响应|不刷新处理
winform主线程执行耗时操作或循环时,会导致窗口不响应,也看不到控件的更新:
方案1:主线程中开启循环,耗时操作放在子线程中处理,控件在主线程中修改。
private async void button1_Click(object sender, EventArgs e) { int i = 0; while (true) { await Task.Run(() => { i++; Thread.Sleep(1000); }); label1.Text = i.ToString(); } }
注意:使用【await Task.Run】开启并等待一个线程,await关键字可以让控制权返回到主线程,保证主线程不卡顿。
方案2:先开子线程,再子线程中开启循环,耗时操作放在子线程中处理,再在子线程里指定主线程来调用修改控件。
private void button1_Click(object sender, EventArgs e) { int i = 0; Task.Run(() => { while (true) { this.Invoke(new Action(() => { label1.Text = i.ToString(); })); i++; Thread.Sleep(1000); } }); }
注意:子线程不能修改主线程创建的控件,需要使用【this.Invoke】指定使用主线程执行一个委托方法。
进阶:双向绑定(MVVM)
参考:WinForm 双向数据绑定 - IT菜鸟的博客 - 博客园 (cnblogs.com)
直接给个实例
using System; using System.ComponentModel; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace 测试 { public partial class Form1 : Form { public MyFormObject from1Obj; public Form1() { InitializeComponent(); from1Obj = new MyFormObject(this); this.label1.DataBindings.Add("text", from1Obj, "TestField"); this.textBox1.DataBindings.Add("text", from1Obj, "TestField"); } private void button1_Click(object sender, EventArgs e) { int i = 0; Task.Run(() => { while (true) { from1Obj.TestField = i.ToString(); i++; Thread.Sleep(1000); } }); } } /// <summary> /// 用来和界面双向绑定的类 /// 要实现双向绑定需要继承System.ComponentModel.INotifyPropertyChange接口。 /// 若不继承此接口则只能单向绑定,对对象属性值的更改不会通知控件更新。 /// </summary> public class MyFormObject : INotifyPropertyChanged { // 绑定的界面 private Form _from; public MyFormObject(Form from) { _from = from; } // 绑定的属性 private string _testField; public string TestField { get => _testField; set { _testField = value; SendChangeInfo("TestField"); } } /// <summary> /// 属性改变后需要调用的方法,触发PropertyChanged事件。 /// 异步修改绑定属性时,使用Form的Invoke方法来避免跨线程修改UI的问题 /// </summary> /// <param name="propertyName">属性名</param> private void SendChangeInfo(string propertyName) { if (this.PropertyChanged != null) { _from.Invoke(new Action(() => { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); })); } } /// <summary> /// 实现的接口。 /// </summary> public event PropertyChangedEventHandler PropertyChanged; } }
运行效果:
修改绑定属性的值,或者修改textBox控件的值。都会自动同步给对方。