当前位置:编程学习 > C#/ASP.NET >>

C#关于线程,报错是 线程间操作无效: 从不是创建控件“textBox4”的线程访问它。

public long str1, str2, str3, str4, str5, sum=0,sum1=0;
            
        public void button1_Click(object sender, EventArgs e)
        {
           
            Thread.CurrentThread.Name = "主线程";
           
            Thread objThreadOne = new Thread(new ThreadStart(fun1));
           
            objThreadOne.Name = "子线程 1";
 
            Thread objThreadTwo = new Thread(new ThreadStart(fun2));
 
            objThreadTwo.Name = "子线程 2";

            objThreadOne.Start();
  
            objThreadTwo.Start();



            objThreadOne.Priority = ThreadPriority.Highest;

            
        }
        void fun1()
        {
            str1 = long.Parse(textBox1.Text);
            str2 = long.Parse(textBox2.Text);
           lock(this)
            
            for (long i = str1; i <= str2; i++)
            {
                sum = sum + i;

            }
            textBox4.Text = sum1.ToString();


        }
        void fun2()
        {
            str1 = long.Parse(textBox1.Text);
            str2 = long.Parse(textBox2.Text);

            lock (this)

            for (long i = str2; i <= str1; i--)
            {
                sum1 = sum1 + i;

            }
            textBox5.Text = sum1.ToString();


        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox4.Text = "";
            textBox1.Text = "";
            textBox2.Text = "";
            str1 = 0;
            str2 = 0;
            sum = 0;
        }

报错线程间操作无效: 从不是创建控件“textBox4”的线程访问它。

我刚刚才学,请大家帮帮忙,谢谢


--------------------编程问答-------------------- 大家能不能在简单易懂的说下,打个比方最好,多线程是什么样 --------------------编程问答-------------------- 委托
textBox4.Invoke(.....) 或 textBox4.BeginInvoke(....)

public delegate void InvokeDelegate();

private void Invoke_Click(object sender, EventArgs e)
{
   myTextBox.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public void InvokeMethod()
{
   myTextBox.Text = "Executed the given delegate";
}

--------------------编程问答-------------------- 神,你讲的太深了,能简单点吗 --------------------编程问答-------------------- 添加个这个2005里面
  System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; --------------------编程问答-------------------- 因为你这个控件是主线程创建的,它依附于创建窗体的主线程.因此,要在子线程去访问占资源的类型,我们需要跨线程调用.textBox4.InvokeRequire用于判断是否需要跨线程,返回True为需要跨线程,此时你需要定义一个委托类来将一个含赋值语句的方法封装起来,通过textBox4.Invoke来调用这个委托.代码如下:
public delegate void SetTextHandler(string text);
private void SetText(string text)
{
   if(textBox4.InvokeRequired==true)
  {
       SetTextHandler set=new SetTextHandler(SetText);//委托的方法参数应和SetText一致
       textBox4.Invoke(set,new object[]{text}); //此方法第二参数用于传入方法,代替形参text
   }
   else
   {
       textBox4.Text=text;
    }
   
}
那么fun2函数可以改写成:
void fun2()
        {
            str1 = long.Parse(textBox1.Text);
            str2 = long.Parse(textBox2.Text);

            lock (this)

            for (long i = str2; i <= str1; i--)
            {
                sum1 = sum1 + i;

            }
            SetText( sum1.ToString());


        }
注意那两句 str1 = long.Parse(textBox1.Text);也需要写成委托形式,读取数据的方法和赋值的方法类型.



--------------------编程问答-------------------- snto(神中神) 的例子是对的!
因为界面对象只能有UI线程(通常为主线程)访问,其他线程只能通过线程间的操作来实现,也就是用委托来实现!
这在.net2.0下是新的限制! --------------------编程问答-------------------- 试下先 --------------------编程问答-------------------- 我现在不知哪里对哪里错,我要好好学这个,这东西学起来太漫长了
--------------------编程问答-------------------- 你先把事件和委托学一下吧 --------------------编程问答-------------------- 上面各处的两个解答都是对的,C#的核心内容之一就是委托,C#里的好多事件都是用委托写的,比如单击按钮的事件,它的委托C#已经帮你写好了。 --------------------编程问答-------------------- private delegate void WritToText();
        private void Writ()
        {
            if (this.InvokeRequired)
            {
                WritToText aa = new WritToText(Writ);
                this.Invoke(aa);
                return;
            }
          //  你的代码
        } --------------------编程问答-------------------- 1、申明委托
   private delegate void UpdateUIDelegate(string msg, int value, bool isMainThread);
2、在 ***_Load() 中写入:
   this.up = new UpdateUIDelegate(this.UpdateUI);
3、函数源码:      
 private void UpdateUI(string msg,int processingValue, bool isMain)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(this.up, new object[] { msg, processingValue , isMain});
                //return;
            }

            this.lblSub.Text = msg;
            this.barSub.Value = processingValue;
        } --------------------编程问答-------------------- 添加:
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
--------------------编程问答-------------------- 申明委托 --------------------编程问答-------------------- 最简单的在load事件中写
Control.CheckForIllegalCrossThreadCalls = false;
最好的用委托 --------------------编程问答-------------------- 在C#中跨线程访问Winform控件 
在程序需要读取CAD文件列表中的文件信息,这是一个非常费时的操作,所以希望通过多线程的方式来实现,并且可以随时中止。由于初次使用多线程,开始的时候采用独立的线程类,该类返回数据,在Thread.Join()方法等待线程结束后写入数据到窗体控件中,结果和单线程没有什么区别;后来查看资料通过使用MethodInvoker解决了这一问题,但是对于线程处理还是概念非常模糊,大家谁有这方面的心得、资料等共享学习学习。
    public partial class frmMain : Form
    {
        private volatile bool _stoped = false;

        private void btFilter_Click(object sender, EventArgs e)
        {
            _stoped = false;
            Thread t = new Thread(new ThreadStart(StartNewThread));
            t.Start();
        }

        private void btStop_Click(object sender, EventArgs e)
        {
            _stoped = true;
        }

        private void GetFileSize()
        {
            btFilter.Enabled = false;
            using (AutoCADConnector CAD = new AutoCADConnector())
            {
                foreach (ListViewItem t in lvSource.Items)
                {
                    if (!_stoped)
                    {
                        AutoCAD.AcadDocument doc = CAD.Application.Documents.Open(t.SubItems[2].Text, true, "");

                        double[] p1 = new double[] { 0, 0, 0 };    //右上角坐标
                        double[] p2 = new double[] { 0, 0, 0 };    //左下角坐标
                        double scale = 0;                                  //缩放比例

                        p1 = (double[])doc.GetVariable("EXTMAX");
                        p2 = (double[])doc.GetVariable("EXTMIN");
                        scale = Convert.ToDouble(doc.GetVariable("DIMSCALE"));

                        double w = Math.Ceiling((p1[0] - p2[0]) / scale);
                        double h = Math.Ceiling((p1[1] - p2[1]) / scale);

                        doc.Close(false, "");

                        t.SubItems[1].Text = string.Format("{0}*{1}  {2}", w, h, scale);
                        //lvSource.Refresh();
                        //Thread.Sleep(100);
                        Application.DoEvents();
                    }
                    else
                        break;
                }
            }
            btFilter.Enabled = true;

        }

        private void StartNewThread()
        {
            MethodInvoker me = new MethodInvoker(this.GetFileSize);
            this.BeginInvoke(me);
        }

    } --------------------编程问答-------------------- mark --------------------编程问答-------------------- mark --------------------编程问答-------------------- 用委托,线程调用 --------------------编程问答-------------------- 委托很强大。 --------------------编程问答-------------------- 委托很好,很强大! --------------------编程问答-------------------- 启用线程安全操作
或者用委托调用控件操作 --------------------编程问答-------------------- 都回答的差不多!线程安全和委托 --------------------编程问答--------------------  NND,我的更郁闷啊,也出现:线程间操作无效: 从不是创建控件“”的线程访问它..
 问题是我没有使用多线程啊...,using threading 都没写..,怎么会出现这个问题呢??? --------------------编程问答-------------------- UI线程

这个线程是用来处理窗体控件等界面资源的创建与用户界面事件响应的

所有对界面资源的线程都要委托给UI线程来执行 --------------------编程问答-------------------- 留下脚印, --------------------编程问答-------------------- 两年了,楼主还没解决吗?哈哈,我也遇到这个问题了。感谢paerxiushi 在5楼把解决方式间接的写出来了。 --------------------编程问答-------------------- 学习!! --------------------编程问答-------------------- 。。。至今仍在~我这算不算挖坟~嘿嘿
错误偶也出了~委托解决~委托对以后学Socket有用的说 --------------------编程问答-------------------- 4楼已给出解决方案,但非安全方法,最好的还是通过委托,让拥有控件的窗体来修改 --------------------编程问答-------------------- 什么破委托看起来晦涩难懂,不知所谓。。微软去死吧。 --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 用委托吧 --------------------编程问答-------------------- mark --------------------编程问答-------------------- 2005以后就这样了,ms就是考虑到线程的安全性问题做的修改。
当一个控件在线程a中被创建,那么这个控件的资源就是属于线程a的,你在线程b中去访问这个控件的资源是要抛出异常的。

一般情况下,控件都是在form的线程中被创建,注意是一般情况下。这个时候,你如果使用了异步,并且在异步方法中要访问或者修改某个控件的值,那么你就必须要指定一个委托,并且将这个委托在form的线程中来使用
--------------------编程问答-------------------- 自己写线程?麻烦了点~
把工具箱中的BackgroundWorker拖进去..问题都解决了
--------------------编程问答--------------------
引用 36 楼 playlinux 的回复:
自己写线程?麻烦了点~
把工具箱中的BackgroundWorker拖进去..问题都解决了


MS是很周到啊,但是周到的我有点不舒服了,几多年后MS如果垮了,这个世界上就会没有程序员了。 --------------------编程问答-------------------- 来这里学习 --------------------编程问答--------------------

//如果是指textbox操作的话,在formload里声明如下也可以了.
Control.CheckForIllegalCrossThreadCalls   =   false;
--------------------编程问答-------------------- C# code
//如果是指textbox操作的话,在formload里声明如下也可以了.
Control.CheckForIllegalCrossThreadCalls   =   false;



这个办法行得通   可是会有问题出现的。最后用委托
 delegate void displayMessage();
        void DisplayMessage()
        {
            if (cb_CardClass.InvokeRequired)
            {
                this.Invoke(new displayMessage(DisplayMessage));
            }
            else
            {
                //代码
            }
        } --------------------编程问答-------------------- 學習了。 --------------------编程问答-------------------- 学习了。 --------------------编程问答-------------------- 学习了。 --------------------编程问答-------------------- 學習了。 --------------------编程问答-------------------- 學習了。 --------------------编程问答-------------------- 4楼正解
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,