线程间操作无效: 从不是创建控件的线程访问它

  在用WinForm做一个后台程序的过程中,我要通过一个Upload按钮打开文件,并将该文件复制到另一文件夹中,同时把源文件的目录复制到一个TextBox中:代码如下:

1、btnUpload按钮事件:

        private void btnUpLoadLeft_Click(object sender, EventArgs e)
        {
            openFileDialog = new OpenFileDialog();
            Thread th = new Thread(delegate() { this.txtLeftPhoto.Text = openFileDialogFileOk("0"); });
            th.SetApartmentState(ApartmentState.STA);
            th.Start();
        }
View Code


2、在btnUpload事件中的openFileDialogFileOk函数:

        /// <summary>
        /// 打开文件夹对话框
        /// </summary>
        /// <param name="dir">left:"1",mid:"2",right:"3"</param>
        private string openFileDialogFileOk(string dir)
        {
            string srcpath = string.Empty;

            if (txtGlassId.Text.Trim().ToString() == string.Empty)
            {
                MessageBox.Show("Please input GlassesId!", "Warning!");
                return string.Empty;//返回string.Empty;
            }

            openFileDialog.Filter = "png files (*.png)|*.png";
            DialogResult dr = openFileDialog.ShowDialog();
            if (dr == DialogResult.OK)
            {
                string srcPath = openFileDialog.FileName;
                string desPath = PublicProperties.desPath + txtGlassId.Text;//目标目录
                string desFile = desPath + string.Format(@"\") + dir + string.Format(@".png");//目标文件
                if (!Directory.Exists(desPath))
                {
                    Directory.CreateDirectory(desPath);
                }
                if (File.Exists(desFile))
                {
                    DialogResult dr1 = MessageBox.Show("There has a photo now,do you want to replace it?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                    if (dr1 == DialogResult.Yes)
                    {
                        File.Delete(desFile);
                        File.Copy(srcPath, desFile);
                        return srcPath;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
                else
                {
                    File.Copy(srcPath, desFile);
                    return srcPath;
                }
            }
            else
            {
                return string.Empty;
            }
        }
View Code


在以上代码的执行过程中,出现错误:线程间操作无效: 从不是创建控件"txtLeftPhoto"的线程访问它.

经搜索,得到以下答案(有两种方式解决): 
  方法1.在窗体构造函数中写Control.CheckForIllegalCrossThreadCalls =false;搜索


  方法2.使用Invoke等委托函数。

  问题原因是:net2.0以后拒绝多线程访问空间,避免空间造成死锁。以前Control.CheckForIllegalCrossThreadCalls =false;默认就是这样,现在默认为true。
  如果不会好几个线程同时操作一个控件用方法1就可以。如果存在多个线程一起操作控件使用方法2

  方法2可以:

                    Invoke(new MethodInvoker(delegate()
                    {
                         //do something...                   

        }));

 

 

另外有在  木月的专栏  中也有基本一致的解答,原文摘抄如下:(建议直接访问原文,原文地址是:http://blog.csdn.net/wangchao0605/article/details/5010864

我们在用线程操作的时候,可能会出现异常:线程间操作无效: 从不是创建控件richTextBox1的线程访问它。因为windows窗体控件不是线程安全的,如果几个线程操作某一控件的状态,可能会使该控件的状态不一致,出现争用或死锁状态。这种情况有以下解决办法:

1. 可以在load时将CheckForIllegalCrossThreadCalls 属性的值设置为 false 。这样进行非安全线程访问时,运行环境就不去检验它是否是线程安全的。但是不推荐这种方法。

2. 利用委托机制实现线程安全。第二种方法就是微软建议采用的跨线程调用的一种通用方法,就是使用代理来实现,就是将你所要操作的代码放到一个代理中,然后将这个代理交给创建这个控件的线程来执行你的代码。

 private delegate void richTextBoxCallBack();
        //建立一个委托

        public void server()
        {
            richTextBoxCallBack callback = delegate()//使用委托
            {
                string ip = getIP();//得到ip地址
                try
                {
                    //获取txt文件的端口号
                    StreamReader smReader = new StreamReader(path, System.Text.Encoding.UTF8);//设置路径  
                    string line;
                    while ((line = smReader.ReadLine()) != null)
                    {
                        //string[] arrStr = line.Split('|');     //分割符 “|”      
                        port = Int32.Parse(line.Trim().ToString());
                        //  MessageBox.Show(port.ToString());
                    }
                    smReader.Close();
                    smReader.Dispose();
                    IPAddress ipAddress = IPAddress.Parse(ip);
                    //创建服务器的套接字
                    listener = new TcpListener(ipAddress, port);
                    //开始监听服务器端口
                    listener.Start(13);

                    //打出提示的信息
                    this.richTextBox1.AppendText("Socket服务器已经启动,正在监听IP" +
                        ip + " 端口号:" + port + "/n");     //从不是创建它的线程访问它的错误???
                    //启动一个新的线程,执行方法this.StartSocketListen,
                    //以便在一个独立的进程中执行确认与客户端Socket连接的操作
                    SocketServiceFlag = true;//服务开始
                    Thread thread = new Thread(new ThreadStart(this.StartSocketListen));
                    thread.Start();
                    this.button1.Enabled = false;
                    this.button2.Enabled = true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("服务器启动错误!!" + ex.Message);
                }
            };
            richTextBox1.Invoke(callback);
             
        }
View Code

建立一个委托 private delegate void richTextBoxCallBack(); 

然后使用委托 richTextBoxCallBack callback = delegate(){}; //使用委托, 声明一个委托类型的变量callback ,{}之间的代码还是原来的方法的代码,最后richTextBox1.Invoke(callback);完成对该控件委托调用。

转载于:https://www.cnblogs.com/zjsjiangnan/p/3476324.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值