WinForm 多线程更新UI控件 进度条(C#,NET,WinForm)

8 篇文章 0 订阅
        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            ThreadMethod method = new ThreadMethod();
            //先订阅一下事件
            method.threadStartEvent += new EventHandler(method_threadStartEvent);
            method.threadEvent += new EventHandler(method_threadEvent);
            method.threadEndEvent += new EventHandler(method_threadEndEvent);
            Task task = new Task(() => { method.runMethod(); });
            task.Start();
        }
        /// <summary>
        /// 线程开始事件,设置进度条最大值
        /// 但是我不能直接操作进度条,需要一个委托来替我完成
        /// </summary>
        /// <param name="sender">ThreadMethod函数中传过来的最大值</param>
        /// <param name="e"></param>
        void method_threadStartEvent(object sender, EventArgs e)
        {
            int maxValue = Convert.ToInt32(sender); 
            this.Invoke(new Action<int>(setMax), maxValue);
        }
        /// <summary>
        /// 线程执行中的事件,设置进度条当前进度
        /// 但是我不能直接操作进度条,需要一个委托来替我完成
        /// </summary>
        /// <param name="sender">ThreadMethod函数中传过来的当前值</param>
        /// <param name="e"></param>
        void method_threadEvent(object sender, EventArgs e)
        {
            int nowValue = Convert.ToInt32(sender); 
            this.Invoke(new Action<int>(setNow), nowValue);
        }
        /// <summary>
        /// 线程完成事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void method_threadEndEvent(object sender, EventArgs e)
        {
            
            MessageBox.Show("执行已经完成!");
            this.Invoke(new Action(setButton));

//只有入参用Action ,如果有返回值用FunC
        }
        public void setButton()
        {
            this.button1.Enabled = true;
        }

        /// <summary>
        /// 我被委托调用,专门设置进度条最大值的
        /// </summary>
        /// <param name="maxValue"></param>
        public void  setMax(int maxValue)
        {
             this.progressBar1.Maximum = maxValue;
            
        }

        /// <summary>
        /// 我被委托调用,专门设置进度条当前值的
        /// </summary>
        /// <param name="nowValue"></param>
        private void setNow(int nowValue)
        {
            this.progressBar1.Value = nowValue;
        }
 public class ThreadMethod
    {
        /// <summary>
        /// 线程开始事件
        /// </summary>
        public event EventHandler threadStartEvent;
        /// <summary>
        /// 线程执行时事件
        /// </summary>
        public event EventHandler threadEvent;
        /// <summary>
        /// 线程结束事件
        /// </summary>
        public event EventHandler threadEndEvent;

        public void runMethod()
        {
            int count = 100;      //执行多少次
            threadStartEvent.Invoke(count, new EventArgs());//通知主界面,我开始了,count用来设置进度条的最大值
            for (int i = 0; i < count; i++)
            {
                Thread.Sleep(100);//休息100毫秒,模拟执行大数据量操作
                threadEvent.Invoke(i, new EventArgs());//通知主界面我正在执行,i表示进度条当前进度
            }
            threadEndEvent.Invoke(new object(), new EventArgs());//通知主界面我已经完成了
        }
    }

 

Winform 中,UI 控件只能在主线程中更新。如果在非主线程中更新 UI 控件,会抛出 "跨线程访问无效: 从不是创建控件的线程访问它" 的异常。因此,我们需要使用以下方式在分线程中更新 UI 控件: 1. 使用 Control.Invoke 方法 使用 Control.Invoke 方法可以将代码添加到 UI 线程的消息队列中执行。这样可以保证在 UI 线程中更新控件,避免跨线程访问异常。 示例代码: ``` private void button1_Click(object sender, EventArgs e) { Thread t1 = new Thread(new ThreadStart(UpdateTextBox)); t1.Start(); } private void UpdateTextBox() { if (textBox1.InvokeRequired) { textBox1.Invoke(new MethodInvoker(delegate { textBox1.Text = "Hello World"; })); } else { textBox1.Text = "Hello World"; } } ``` 2. 使用 BackgroundWorker 组件 BackgroundWorker 组件是一个用于执行异步操作的组件,在操作完成后可以安全地更新 UI 控件。它具有一个 ProgressChanged 事件和一个 RunWorkerCompleted 事件,可以在这两个事件中更新 UI 控件。 示例代码: ``` private void button1_Click(object sender, EventArgs e) { backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // 在这里执行耗时的操作 } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // 在这里更新 UI 控件 } private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // 在这里更新 UI 控件 } ``` 以上两种方式都可以在分线程中安全地更新 UI 控件,具体使用哪种方式取决于实际情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值