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控件的值。都会自动同步给对方。

 

posted @ 2022-10-18 16:01  Ariter  阅读(1467)  评论(0编辑  收藏  举报