C# invoke 异步编程 V2 (跨线程调用控件)

上一篇已经实现了异步功能,不过数据是通过控制台输出。如果需要在控件中显示的话,那么就涉及到跨线程调用控件的问题了

winform规定 不能跨线程访问其他线程创建的对象 

以下是我修改后的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ZQ学习demo
{
    public partial class 异步编程 : Form
    {
        public delegate string delegateObj(string paht);
        public 异步编程()
        {
            InitializeComponent();
            delobj = new delegateObj(copyFile);
        }
        delegateObj delobj=null;
        /// <summary>
        /// 同步拷贝文件,并输出文件名称
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            String[] paths = Directory.GetFiles(@"F:\迅雷下载");
            for (int i = 0; i < paths.Length; i++)
            {
                this.listBox1.Items.Add(copyFile(paths[i]));
            }
        }
        /// <summary>异步拷贝文件,并输出文件名
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            
            String[] paths = Directory.GetFiles(@"F:\迅雷下载");
            for (int i = 0; i < paths.Length; i++)
            {
                delobj.BeginInvoke(paths[i], null, null);//最后一个参数是回调状态
            }
        }
        public void callback(IAsyncResult result)
        {
            //if (this.listBox1.InvokeRequired)
            //{
            //    this.listBox2.Invoke(delobj);
            //    this.listBox2.Items.Add(result.AsyncState.ToString() + "复制成功");
            //}

            //delobj.EndInvoke(result);
            //this.listBox2.Items.Add(result.AsyncState.ToString() + "复制成功");

        }
        /// <summary>
        /// 拷贝文件用
        /// </summary>
        /// <param name="filename"></param>
        public string copyFile(string filename)
        {
            if (filename.EndsWith("desktop.ini"))
                return "desktop.ini";
            if (File.Exists(@"F:\迅雷下载2\" + Path.GetFileName(filename)))
            {
                File.Delete(@"F:\迅雷下载2\" + Path.GetFileName(filename));
            }
            File.Copy(filename, @"F:\迅雷下载2\" + Path.GetFileName(filename));
            if(this.listBox2.InvokeRequired)
            {
                Action<string> de=(x)=>{this.listBox2.Items.Add(Path.GetFileName(x));};
                this.listBox2.Invoke(de, new string[] { filename });
            }else
            {
                this.listBox2.Items.Add(Path.GetFileName(filename));
            }
            
            return Path.GetFileName(filename);
        }
    }
}

 

 

跨线程调用控件的其他解决办法(转 https://www.cnblogs.com/TankXiao/p/3348292.html) 

第一种办法:禁止编译器对跨线程访问做检查

这是最简单的办法, 相当于不检查线程之间的冲突,允许各个线程随便乱搞,最后Lable1控件的值是什么就难以预料了 (不推荐使用这种方法)

        public Form1()
        {
            InitializeComponent();
            // 加入这行
            Control.CheckForIllegalCrossThreadCalls = false;
        }

第二种办法: 使用delegate和invoke来从其他线程中调用控件

调用控件的invoke方法,就可以控制控件了,例如

复制代码

        private void button2_Click(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
            thread1.Start("更新Label");
        }

        private void UpdateLabel2(object str)
        {
            if (label2.InvokeRequired)
            {
                // 当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它
                Action<string> actionDelegate = (x) => { this.label2.Text = x.ToString(); };
                // 或者
                // Action<string> actionDelegate = delegate(string txt) { this.label2.Text = txt; };
                this.label2.Invoke(actionDelegate, str);
            }
            else
            {
                this.label2.Text = str.ToString();
            }
        }

复制代码

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值