精华内容
下载资源
问答
  • 主要介绍了C#中跨线程访问控件问题解决方案,有需要的朋友可以参考一下
  • C# 跨线程访问UI线程控件 在C#中,由于使用线程和调用UI的线程属于两个不同的线程,如果在线程中直接设置UI元素的属性,此时就会出现跨线程错误。    下面介绍两种解决方案  第一种:使用控件自带的Invoke或者...
  • C#跨线程访问

    2019-05-17 09:59:00
    C# 的应用程序开发, 我们经常要把UI线程...第一种办法:禁止编译器对跨线程访问做检查 第二种办法: 使用delegate和invoke来从其他线程调用控件 第三种办法: 使用delegate和BeginInvoke来从其他线程控制控...

    在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应。  同时我们又需要在工作线程中更新UI界面上的控件,

    下面介绍几种常用的方法

     

    阅读目录

    1. 线程间操作无效
    2. 第一种办法:禁止编译器对跨线程访问做检查
    3. 第二种办法: 使用delegate和invoke来从其他线程中调用控件
    4. 第三种办法: 使用delegate和BeginInvoke来从其他线程中控制控件
    5. 第四种办法: 使用BackgroundWorker组件
    6. 源代码下载

     

    线程间操作无效

    界面上有一个button和一个label,  点击button会启动一个线程来更新Label的值

    复制代码
            private void button1_Click(object sender, EventArgs e)
            {
                Thread thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
                thread1.Start("更新Label");
            }
    
            private void UpdateLabel(object str)
            {
                this.label1.Text = str.ToString();
            }
    复制代码

    运行后, 程序会报错 "跨线程操作无效,从不是创建"label1"的线程访问它"

     

    这是因为.NET禁止了跨线程调用控件, 否则谁都可以操作控件,最后可能造成错误。   

     

    下面介绍几种跨线程调用控件的方法

     

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

    这是最简单的办法, 相当于不检查线程之间的冲突,允许各个线程随便乱搞,最后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();
                }
            }
    复制代码

     

    第三种办法: 使用delegate和BeginInvoke来从其他线程中控制控件

    只要把上面的 this.label2.Invoke(actionDelegate, str); 中的 Invoke 改为BeginInvoke方法就可以了

    Invoke方法和BeginInvoke方法的区别是

    Invoke方法是同步的, 它会等待工作线程完成,

    BeginInvoke方法是异步的, 它会另起一个线程去完成工作线程

     form.Invoke((Action)(() =>
                            {
                                form.Text = "数据传送完成,正在写入Flash";

                            }));

    第四种办法: 使用BackgroundWorker组件(推荐使用这个方法)

    BackgroundWorker是.NET里面用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。耗时的操作(如下载和数据库事务)。用法简单 

    复制代码
            private void button4_Click(object sender, EventArgs e)
            {
                using (BackgroundWorker bw = new BackgroundWorker())
                {
                    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                    bw.RunWorkerAsync("Tank");
                }         
            }
    
            void bw_DoWork(object sender, DoWorkEventArgs e)
            {       
                // 这里是后台线程, 是在另一个线程上完成的
                // 这里是真正做事的工作线程
                // 可以在这里做一些费时的,复杂的操作
                Thread.Sleep(5000);
                e.Result = e.Argument + "工作线程完成";
            }
    
            void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了 
                this.label4.Text = e.Result.ToString(); 
            }
    复制代码

    转载于:https://www.cnblogs.com/yuesebote/p/10879775.html

    展开全文
  • C#跨线程访问控件

    2013-03-17 14:28:48
    C#跨线程访问控件,用了线程池和Action委托和Control的Invoke方法
  • c#中跨线程访问

    2014-11-18 14:37:00
    1 Thread thread = new Thread(threadRun); thread.IsBackground = true; thread.Start(); 2 private void threadRun() { MethodInvok...

     

     

             1     Thread thread = new Thread(threadRun);
                thread.IsBackground = true;
                thread.Start();

     

        2    private void threadRun()
            {
                MethodInvoker In = new MethodInvoker(run);
                this.BeginInvoke(In);
            }

          3    private void run()
            {
                this.tslInfo.Text = "Npoi大爷的";
            }

    转载于:https://www.cnblogs.com/cdaq/p/4105727.html

    展开全文
  • C#中跨线程访问

    2018-05-25 10:05:00
    https://blog.csdn.net/zhangxiao93/article/details/44730863 https://blog.csdn.net/zhongjiekangping/article/details/4563639 转载于:https://www.cnblogs.com/janghe/p/9086956.html
    展开全文
  • C#中跨线程访问控件

    2019-10-07 23:57:12
    第二种方法是禁止编译器对跨线程访问作检查,可以实现访问,但是出不出错不敢保证Control.CheckForIllegalCrossThreadCalls = false; 最近我在做一个项目,遇到了跨线程要去访问页面控件.但是总是提示出错,不能在...

    net 原则上禁止跨线程访问控件,因为这样可能造成错误的发生,推荐的解决方法是采用代理,用代理方法来间接操作不是同一线程创建的控件。 

    第二种方法是禁止编译器对跨线程访问作检查,可以实现访问,但是出不出错不敢保证Control.CheckForIllegalCrossThreadCalls = false;

    最近我在做一个项目,遇到了跨线程要去访问页面控件.但是总是提示出错,不能在其它线程中修改创建控件的线程的控件的值,后来采用了匿名代理,结果很轻松地解决了.解决过程如下:
    首先在窗体上,创建一个listbox,lable.

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Text;
     7 using System.Windows.Forms;
     8 using System.Threading;
     9 
    10 namespace AccessControl
    11 {
    12     public partial class Form1 : Form
    13     {      
    14         public Form1()
    15         {
    16             InitializeComponent();
    17         }
    18 
    19         private void Form1_Load(object sender, EventArgs e)
    20         {  
    21             Thread newthread = new Thread(new ThreadStart(BackgroundProcess));
    22             newthread.Start();         
    23 
    24         }
    25 
    26         /// <summary> 
    27         /// 定义一个代理 
    28         /// </summary> 
    29         private delegate void CrossThreadOperationControl();
    30 
    31         private void BackgroundProcess()
    32         {
    33             // 将代理实例化为一个匿名代理 
    34             CrossThreadOperationControl CrossDelete = delegate()          
    35             {            
    36                 int i = 1;
    37                 while (i<5)
    38                 {
    39                    // 向列表框增加一个项目 
    40                     listBox1.Items.Add("Item " + i.ToString());                    
    41                     i++;
    42                 }
    43                 label1.Text = "我在新线程里访问这个lable!";
    44                 listBox1.Items.Add(label1.Text);
    45             }  ;
    46             listBox1.Invoke(CrossDelete);           
    47         }       
    48 
    49     }
    50 }

     

    希望这个小技巧能够对你的的学习和工作有所帮助.若有更好的办法来解决跨线程访问控件的问题,不防也拿出来大家分享一下.

    C#跨线程访问控件运行时错误,使用MethodInvoker即可解决:

    原代码:

            

     1 private void btnOK_Click(object sender, EventArgs e)
     2         {
     3             tslInfo.Text = "请稍候...";
     4 
     5 
     6             Thread td = new Thread(new ThreadStart(run));
     7             td.Start();
     8         }
     9 
    10 
    11         /// <summary>
    12         /// 线程方法
    13         /// </summary>
    14         private void run()
    15         {
    16             this.tslInfo.Text = "就绪";
    17         }

     

    修改后:


            

     1 private void btnOK_Click(object sender, EventArgs e)
     2         {
     3             tslInfo.Text = "请稍候...";
     4 
     5 
     6             Thread td = new Thread(new ThreadStart(threadRun));
     7             td.Start();
     8         }
     9 
    10 
    11         /// <summary>
    12         /// 原线程方法
    13         /// </summary>
    14         private void run()
    15         {
    16             this.tslInfo.Text = "就绪";
    17         }
    18 
    19         /// <summary>
    20         /// 线程方法
    21         /// </summary>
    22         private void threadRun()
    23         {
    24             MethodInvoker In = new MethodInvoker(run);
    25             this.BeginInvoke(In);
    26         }

     

    我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题。然而我们并不能用传统方法来做这个问题,下面我将详细的介绍。

          首先来看传统方法:

         

     1  public partial class Form1 : Form
     2     {
     3         public Form1()
     4         {
     5             InitializeComponent();
     6         }
     7         private void Form1_Load(object sender, EventArgs e)
     8         {
     9             Thread thread = new Thread(ThreadFuntion);
    10             thread.IsBackground = true;
    11             thread.Start();
    12         }
    13         private void ThreadFuntion()
    14         {
    15             while (true)
    16             {
    17                 this.textBox1.Text = DateTime.Now.ToString();
    18                 Thread.Sleep(1000);
    19             }
    20         }
    21     }

     

           运行这段代码,我们会看到系统抛出一个异常:Cross-thread operation not valid:Control 'textBox1' accessed from a thread other than the thread it was created on . 这是因为.net 2.0以后加强了安全机制,不允许在winform中直接跨线程访问控件的属性。那么怎么解决这个问题呢,下面提供几种方案。

          第一种方案,我们在Form1_Load()方法中加一句代码:

          

    1 private void Form1_Load(object sender, EventArgs e)
    2       {
    3             Control.CheckForIllegalCrossThreadCalls = false;
    4             Thread thread = new Thread(ThreadFuntion);
    5             thread.IsBackground = true;
    6             thread.Start();
    7         }


          加入这句代码以后发现程序可以正常运行了。这句代码就是说在这个类中我们不检查跨线程的调用是否合法(如果没有加这句话运行也没有异常,那么说明系统以及默认的采用了不检查的方式)。然而,这种方法不可取。我们查看CheckForIllegalCrossThreadCalls 这个属性的定义,就会发现它是一个static的,也就是说无论我们在项目的什么地方修改了这个值,他就会在全局起作用。而且像这种跨线程访问是否存在异常,我们通常都会去检查。如果项目中其他人修改了这个属性,那么我们的方案就失败了,我们要采取另外的方案。

          下面来看第二种方案,就是使用delegate和invoke来从其他线程中控制控件信息。网上有很多人写了这种控制方式,然而我看了很多这种帖子,表明上看来是没有什么问题的,但是实际上并没有解决这个问题,首先来看网络上的那种不完善的方式:

     1 public partial class Form1 : Form
     2     {
     3         private delegate void FlushClient();//代理
     4         public Form1()
     5         {
     6             InitializeComponent();
     7         }
     8         private void Form1_Load(object sender, EventArgs e)
     9         {
    10             Thread thread = new Thread(CrossThreadFlush);
    11 
    12             thread.IsBackground=true;
    13             thread.Start();
    14         }
    15 
    16         private void CrossThreadFlush()
    17         {
    18             //将代理绑定到方法 
    19             FlushClient fc = new FlushClient(ThreadFuntion);
    20             this.BeginInvoke(fc);//调用代理
    21         }
    22         private void ThreadFuntion()
    23         {
    24             while (true)
    25             {
    26                 this.textBox1.Text = DateTime.Now.ToString();
    27                 Thread.Sleep(1000);
    28             }
    29         }
    30     }

     

           使用这种方式我们可以看到跨线程访问的异常没有了。但是新问题出现了,界面没有响应了。为什么会出现这个问题,我们只是让新开的线程无限循环刷新,理论上应该不会对主线程产生影响的。其实不然,这种方式其实相当于把这个新开的线程“注入”到了主控制线程中,它取得了主线程的控制。只要这个线程不返回,那么主线程将永远都无法响应。就算新开的线程中不使用无限循环,使可以返回了。这种方式的使用多线程也失去了它本来的意义。

           现在来让我们看看推荐的解决方案(建议用该方案):

     1 public partial class Form1 : Form
     2     {
     3         private delegate void FlushClient();//代理
     4         public Form1()
     5         {
     6             InitializeComponent();
     7         }
     8         private void Form1_Load(object sender, EventArgs e)
     9         {
    10             Thread thread = new Thread(CrossThreadFlush);
    11             thread.IsBackground = true;
    12             thread.Start();
    13         }
    14 
    15         private void CrossThreadFlush()
    16         {
    17             while (true)
    18             {
    19                 //将sleep和无限循环放在等待异步的外面
    20                 Thread.Sleep(1000);
    21                 ThreadFunction();
    22             }
    23         }
    24         private void ThreadFunction()
    25         {
    26             if (this.textBox1.InvokeRequired)//等待异步
    27             {
    28                 FlushClient fc = new FlushClient(ThreadFunction);
    29                 this.Invoke(fc);//通过代理调用刷新方法
    30             }
    31             else
    32             {
    33                 this.textBox1.Text = DateTime.Now.ToString();
    34             }
    35         }
    36     }

     

           运行上述代码,我们可以看到问题已经被解决了,通过等待异步,我们就不会总是持有主线程的控制,这样就可以在不发生跨线程调用异常的情况下完成多线程对winform多线程控件的控制了。

           对于深山老林提出的问题,我最近找到了更优的解决方案,利用了delegate的异步调用,大家可以看看:

     1 public partial class Form1 : Form
     2     {
     3         private delegate void FlushClient();//代理
     4         public Form1()
     5         {
     6             InitializeComponent();
     7         }
     8         private void Form1_Load(object sender, EventArgs e)
     9         {
    10             Thread thread = new Thread(CrossThreadFlush);
    11             thread.IsBackground = true;
    12             thread.Start();
    13         }
    14 
    15         private void CrossThreadFlush()
    16         {
    17 
    18              FlushClient=new FlushClient(ThreadFunction);
    19 
    20              FlushClient.BeginInvoke(null,null);
    21         }
    22         private void ThreadFunction()
    23         {
    24 
    25               while (true)
    26             {
    27                 this.textBox1.Text = DateTime.Now.ToString();
    28                 Thread.Sleep(1000);
    29             }
    30 
    31         }
    32     }

     

         这种方法也可以直接简化为(因为delegate的异步就是开了一个异步线程):

     1 public partial class Form1 : Form
     2     {
     3         private delegate void FlushClient();//代理
     4         public Form1()
     5         {
     6             InitializeComponent();
     7         }
     8         private void Form1_Load(object sender, EventArgs e)
     9         {
    10             Thread thread = new Thread(CrossThreadFlush);
    11              FlushClient=new FlushClient(ThreadFunction);
    12 
    13              FlushClient.BeginInvoke(null,null);
    14         }
    15 
    16          private void ThreadFunction()
    17         {
    18 
    19               while (true)
    20             {
    21                 this.textBox1.Text = DateTime.Now.ToString();
    22                 Thread.Sleep(1000);
    23             }
    24 
    25         }
    26     }

     

    转载于:https://www.cnblogs.com/hanc/p/3685995.html

    展开全文
  • C# 跨线程访问控件

    千次阅读 2018-04-06 00:21:08
    因为C#安全机制的问题,不是本线程创建的控件,是不能...二、创建委托,利用C#的Invoke 或 beginInvoke 方法从创建控件的线程来执行跨线程调用; 三、利用BackgroundWorker组件 和 DoWorkEventHandler 、 RunWorker...
  • C#中遇到的多线程问题,该程序为跨线程访问控件的实例
  • C#跨线程访问UI(BeginInvoke) public void Righttesting() { if (InvokeRequired) { BeginInvoke(new Action(() => Righttesting())); return; } //通过这个方法就可以在其他线程随意访问UI,不会...
  • C#中跨线程访问控件处理方式

    千次阅读 2018-06-19 14:40:23
    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件A(由线程Tread A创建)的InvokeRequired属性值为真时,说明有一个创建它以外的线程(Tread B)想访问它。此时,若Tread B线程...
  • c#跨线程访问控件

    2016-05-26 16:57:01
    C#中,在线程中(包括 BackgroundWorker 控件)访问主线程UI时会抛出异常:因为.net禁止了跨线程调用控件。下面用一个办法来进行跨线程的调用,且不阻塞控件。以给控件赋Text值为例,因为这个比较实用。 private ...
  • 通过反射技术,将异步加载的数据,安全的跨线程会显到UI界面.使用简单
  • 第二种方法是禁止编译器对跨线程访问作检查,可以实现访问,但是出不出错不敢保证Control.CheckForIllegalCrossThreadCalls = false; 最近我在做一个项目,遇到了跨线程要去访问页面控件.但是总是提示出错,不能在...
  • c# 跨线程访问控件

    2020-09-29 20:22:50
    这样可以实现在另外的线程访问控件,但是这种方法并不安全,不能保证C#跨线程访问控件的运行时错误。 // 在初始化控件后就可以把这个属性设置为false,编译器就不会对跨线程访问做检查 public Form1() { Initialize...
  • C#跨线程回调delegate和invoke详解在C#应用开发UI线程和工作线程分开多线程解决方案阅读目录主要有以下的几个方法1.在工程创建一个静态是static数据盛放类用类名调用2.禁止编译器对跨线程检查检测3.定义回调函数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,888
精华内容 7,555
关键字:

c#跨线程访问

c# 订阅