• 先说明本人水平不高 ...然后提示,调用线程必须为 STA,因为许多 UI 组件都需要。 现在想知道怎么能让MainWindow向这个类中传递此TextBox。 这个类是定时运行的,非主界面启动的,而且在主界面前加载。
  • C#多线程解决界面卡死问题的完美解决方案,简化了之前的写法,更容易记住和理解 C#多线程解决界面卡死问题的完美解决方案,简化了之前的写法,更容易记住和理解
  • c#多线程刷新界面

    2016-04-10 20:14:03
    c#多线程刷新界面 标签: 多线程c#threadwinformobjectstring 2010-04-18 20:50 2031人阅读 评论(1) 收藏 举报  分类:   c#(84)  这个问题也不知道难倒了多少C#豪杰。比起MFC的界面...
     

    c#多线程刷新界面

    标签: 多线程c#threadwinformobjectstring
     2031人阅读 评论(1) 收藏 举报
     分类:
     

    这个问题也不知道难倒了多少C#豪杰。比起MFC的界面刷新,在WINFORM中来实现多线程刷新真是很痛苦,故写此文。

    多线程刷新界面主要用到多线程,委托,线程安全、事件等一系列高难度的C#操作。

    关于委托和事件,这有一篇很易懂的文章:hi.baidu.com/anglecloudy/blog/item/a52253ee804d052f2df534ab.html

    ===============================================

    先从一个简单的例子说起,是一个没有考虑线程安全的写法:

    先在一个FORM类里面定义一个委托和事件:

      protected delegate void UpdateControlText1(string str);
            //定义更新控件的方法
            protected void updateControlText(string str)
            {
                this.lbStatus.Text = str ;
                return;
            }

    在线程函数里面加上下面的内容

    UpdateControlText1 update = new UpdateControlText1(updateControlText);//定义委托
    this.Invoke(update, "OK");//调用窗体Invoke方法

    这个线程函数必须是类的线程函数,这样用很方便,但有很高的局限性,下面来说个复杂的。

    ==============================================

    先定义一个独立的类

    public class MoreTime
        {
            
    public delegate void InvokeOtherThead( int i);//委托

            
    public InvokeOtherThead MainThread;//事件

            
    public void WaitMoreTime()
            {
                
                
    for ( int i = 0 ; i < 20 ;i ++ )
                {
                    Thread.Sleep(
     2000 );
                    
                    MainThread(i);//调用事件
                }
            }
        }

    主函数

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click( object sender, EventArgs e)
            {
                MoreTime mt = new MoreTime();
                mt.MainThread = new MoreTime.InvokeOtherThead(AddToList); //事件响应
                ThreadStart start = new ThreadStart(mt.WaitMoreTime);//起动线程
                Thread thread = new Thread(start);
                thread.Start();
            }

            public void AddToList( int i)   //事件响应函数
            {
                if ( this .listBox1.InvokeRequired)
                {
                    MoreTime mt = new MoreTime();
                    mt.MainThread = new MoreTime.InvokeOtherThead(AddToList);

                    this .Invoke(mt.MainThread, new object [] { i});

                }
                else 
                {
                    listBox1.Items.Add(i.ToString());   //这里一定要是可以瞬时完成的函数
                }
            }
        }

    展开全文
  • C#多线程刷新界面卡死测试背景要点Demo关键代码完成代码下载 背景 在上位机程序开发过程中,不可避免的会用到多线程,如处理Socket通信、PLC读取、界面数据实时刷新等。在某个项目中由于开启的线程很多,出现了不...

    C#多线程刷新界面卡死测试

    背景

    在上位机程序开发过程中,不可避免的会用到多线程,如处理Socket通信、PLC读取、界面数据实时刷新等。在某个项目中由于开启的线程很多,出现了不定期界面卡死状况,但后台线程还在运行,日志还在输出。为了解决这个问题,特写了模拟程序进行问题复现。顺便把过程分享一下。

    要点

    1、区分Control.BeginInvoke和Control.Invoke的用法
    2、区分System.Timers.Timer、System.Threading.ThreadPool、System.Threading.Thread

    Demo

    创建一个WinForm应用程序,把工程属性的输出类型设置为控制台应用程序,方便运行时查看日志。

    关键代码

    BasicInvoker

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WinApp
    {
        /// <summary>
        /// 调用器
        /// </summary>
        public class BasicInvoker
        {
            public delegate void Invoke(); 
    
            private Form form = null;
            private TextBox txt = null;
            private object value = String.Empty;
    
            public BasicInvoker(Form form, TextBox txt, object value)
            {
                this.form = form;
                this.txt = txt;
                this.value = value;
            }
    
            public void SetValue()
            {
                if (this.form != null && !this.form.IsDisposed)
                {
                    if (this.form.InvokeRequired)
                    {
                        Delegate d = new Invoke(this.DoWork);
                        try
                        {
                            this.form.Invoke(d, null);
                            //this.form.BeginInvoke(d);
                        }
                        catch(Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        this.DoWork();
                    }
                }
            }
    
            public void DoWork()
            {
                if (this.txt != null)
                {
                    this.txt.Text = this.value.ToString();
                    Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + "  " +  this.value.ToString() + "...1");
                    System.Threading.Thread.Sleep(200);
                    Console.WriteLine(String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}", DateTime.Now) + "  " + this.value.ToString() + "...2");
                }
            }
        }
    }
    
    

    FrmTest

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WinApp
    {
        public partial class FrmTester : Form
        {
            #region 变量定义
    
            private System.Timers.Timer timer1 = null;
            private System.Timers.Timer timer2 = null;
            private System.Timers.Timer timer3 = null;
    
            private System.Threading.Thread thread1 = null;
            private System.Threading.Thread thread2 = null;
            private System.Threading.Thread thread3 = null;
    
            #endregion
    
            #region 构造方法
    
            public FrmTester()
            {
                InitializeComponent();
            }
    
            #endregion
    
            #region 事件处理
    
            private void Form1_Load(object sender, EventArgs e)
            {
                
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                if (timer1 == null)
                {
                    timer1 = new System.Timers.Timer();
                    timer1.Interval = 500;
                    timer1.Elapsed += t1_Elapsed;
                    timer1.Start();
                }
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                if (timer2 == null)
                {
                    timer2 = new System.Timers.Timer();
                    timer2.Interval = 500;
                    timer2.Elapsed += t2_Elapsed;
                    timer2.Start();
                }
            }        
    
            private void button3_Click(object sender, EventArgs e)
            {
                if (timer3 == null)
                {
                    timer3 = new System.Timers.Timer();
                    timer3.Interval = 500;
                    timer3.Elapsed += t3_Elapsed;
                    timer3.Start();
                }
            }
    
            private void button4_Click(object sender, EventArgs e)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack1));
            }
    
            private void button5_Click(object sender, EventArgs e)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack2));
            }
    
            private void button6_Click(object sender, EventArgs e)
            {
                System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.CallBack3));
            }
    
            private void button7_Click(object sender, EventArgs e)
            {
                if (this.thread1 == null)
                {
                    this.thread1 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack1));
                    this.thread1.Start();
                }
            }
    
            private void button8_Click(object sender, EventArgs e)
            {
                if (this.thread2 == null)
                {
                    this.thread2 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack2));
                    this.thread2.Start();
                }
            }
    
            private void button9_Click(object sender, EventArgs e)
            {
                if (this.thread3 == null)
                {
                    this.thread3 = new System.Threading.Thread(new System.Threading.ThreadStart(this.CallBack3));
                    this.thread3.Start();
                }
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                Console.WriteLine("FormClosing...");
                
                if (this.timer1 != null)
                {
                    this.timer1.Stop();
                    this.timer1.Dispose();
                }
                if (this.timer2 != null)
                {
                    this.timer2.Stop();
                    this.timer2.Dispose();
                }
                if (this.timer3 != null)
                {
                    this.timer3.Stop();
                    this.timer3.Dispose();
                }
    
                if (this.thread1 != null)
                {
                    //if (this.thread1.ThreadState == System.Threading.ThreadState.Running)
                    {
                        this.thread1.Abort();
                    }
                }
    
                if (this.thread2 != null)
                {
                    //if (this.thread2.ThreadState == System.Threading.ThreadState.Running)
                    {
                        this.thread2.Abort();
                    }
                }
    
                if (this.thread3 != null)
                {
                    //if (this.thread3.ThreadState == System.Threading.ThreadState.Running)
                    {
                        this.thread3.Abort();
                    }
                }
            }
    
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                Console.WriteLine("FormClosed...");
            }  
    
            #endregion
    
            #region 定时处理方法定义
    
            private void t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                //lock(Global.PublicVar.Instance.Locker1)
                lock (String.Empty)
                {
                    BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
                    invoker.SetValue();
                }
            }
    
            private void t2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                ////lock (Global.PublicVar.Instance.Locker1)
                lock (String.Empty)
                {
                    BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
                    invoker.SetValue();
                }
            }
    
            private void t3_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {
                //lock (Global.PublicVar.Instance.Locker1)
                lock (String.Empty)
                {
                    BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
                    invoker.SetValue();
                }
            }
    
            public void CallBack1(object state)
            {
                while(true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock(String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            public void CallBack2(object state)
            {
                while (true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock(String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            public void CallBack3(object state)
            {
                while (true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock(String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            public void CallBack1()
            {
                while (true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock (String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, Guid.NewGuid().ToString());
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            public void CallBack2()
            {
                while (true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock (String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            public void CallBack3()
            {
                while (true)
                {
                    //lock (Global.PublicVar.Instance.Locker1)
                    lock (String.Empty)
                    {
                        BasicInvoker invoker = new BasicInvoker(this, this.textBox1, "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
                        invoker.SetValue();
                    }
                    System.Threading.Thread.Sleep(500);
                }
            }
    
            #endregion
        }
    }
    
    

    运行图:
    在这里插入图片描述
    在这里插入图片描述
    运行结果:
    一、使用Control.BeginInvoke的情况

    public void SetValue()
            {
                if (this.form != null && !this.form.IsDisposed)
                {
                    if (this.form.InvokeRequired)
                    {
                        Delegate d = new Invoke(this.DoWork);
                        try
                        {
                            //this.form.Invoke(d, null);
                            this.form.BeginInvoke(d);
                        }
                        catch(Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        this.DoWork();
                    }
                }
            }
    

    1.1、System.Timers.Timer开启2以上很快界面卡死,日志正常输出。
    1.2、System.Threading.ThreadPool开启3个时,运行一会界面卡死,日志正常输出。
    1.3、System.Threading.Thread开启3个时,运行一会界面卡死,日志正常输出。
    二、使用Control.Invoke的情况

    public void SetValue()
            {
                if (this.form != null && !this.form.IsDisposed)
                {
                    if (this.form.InvokeRequired)
                    {
                        Delegate d = new Invoke(this.DoWork);
                        try
                        {
                            this.form.Invoke(d, null);
                            //this.form.BeginInvoke(d);
                        }
                        catch(Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        this.DoWork();
                    }
                }
            }
    

    2.1、System.Timers.Timer开启3个时很快界面卡死,日志正常输出。
    2.2、System.Threading.ThreadPool开启3个时,界面正常操作,日志正常输出。
    2.3、System.Threading.Thread开启3个时,界面正常操作,日志正常输出。

    测试总结:
    1、System.Threading.ThreadPool与System.Threading.Thread运行效果基本相同。
    2、在多线程刷新界面时尽量通过Control.Invoke调用委托实现。

    完成代码下载

    完整代码下载

    展开全文
  • //多线程刷新界面主要用到多线程,委托,线程安全、事件等一系列高难度的C#操作。 //关于委托和事件,这有一篇很易懂的文章:hi.baidu.com/anglecloudy/blog/item/a52253ee804d052f2df534ab.html //=======...
    //这个问题也不知道难倒了多少C#豪杰。比起MFC的界面刷新,在WINFORM中来实现多线程刷新真是很痛苦,故写此文。
    //多线程刷新界面主要用到多线程,委托,线程安全、事件等一系列高难度的C#操作。
    //关于委托和事件,这有一篇很易懂的文章:hi.baidu.com/anglecloudy/blog/item/a52253ee804d052f2df534ab.html
    //===============================================
    //先从一个简单的例子说起,是一个没有考虑线程安全的写法:
    //先在一个FORM类里面定义一个委托和事件:
      protected delegate void UpdateControlText1(string str);
    //定义更新控件的方法
    protected void updateControlText(string str)
    {
        this.lbStatus.Text = str ;
        return;
    }
    //在线程函数里面加上下面的内容
    UpdateControlText1 update = new UpdateControlText1(updateControlText);//定义委托
    this.Invoke(update, "OK");//调用窗体Invoke方法
    //这个线程函数必须是类的线程函数,这样用很方便,但有很高的局限性,下面来说个复杂的。


    //==============================================
    //先定义一个独立的类
    public class MoreTime
    {
        public delegate void InvokeOtherThead(int i);//委托


        public InvokeOtherThead MainThread;//事件


        public void WaitMoreTime()
        {
            for (int i= 0 ; i<20;i++)
            {
                Thread.Sleep(2000);
                MainThread(i);//调用事件
            }
        }
    }
    //主函数
    public partial class Form1 : Form
    {
        public Form1()
        {
        InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            MoreTime mt = new MoreTime();
            mt.MainThread = new MoreTime.InvokeOtherThead(AddToList); //事件响应
            ThreadStart start = new ThreadStart(mt.WaitMoreTime);//起动线程
            Thread thread = new Thread(start);
            thread.Start();
        }


        public void AddToList(int i)   //事件响应函数
        {
            if (this.listBox1.InvokeRequired)
            {
                MoreTime mt = new MoreTime();
                mt.MainThread = new MoreTime.InvokeOtherThead(AddToList);
                this.Invoke(mt.MainThread, new object[] { i});
            }
            else
            {
               listBox1.Items.Add(i.ToString());   //这里一定要是可以瞬时完成的函数
            }
        }
    }
    展开全文
  • C#线程调用控件

    2017-12-10 20:12:13
    线程调用控件 http://www.cnblogs.com/TankXiao/p/3348292.html#backgroudworker在C# 的应用程序开发中, 我们经常要把UI线程和工作线程分开,防止界面停止响应。 同时我们又需要在工作线程中更新UI界面上的控件...

    C# 跨线程调用控件

    http://www.cnblogs.com/TankXiao/p/3348292.html#backgroudworker

    在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方法是异步的, 它会另起一个线程去完成工作线程

     

    第四种办法: 使用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(); 
            }
    复制代码

     

    源代码下载

    请用VS2010打开【下载】

     

     

     


    分类: C# Winform
    24
    0


    « 上一篇:C# 技巧(1) C# 转换时间戳
    » 下一篇:TestNG 入门教程
    posted on 2014-10-04 07:12 小坦克 阅读(25497) 评论(15编辑 收藏



    #1楼 2014-10-04 07:21 | 我爱浓咖啡  
    不错,学习了

    #2楼 2014-10-04 09:08 | 代号小子  
    我知道2种,,原来还有啊

    #3楼 2014-10-04 09:32 | LyBlog  
    还有一种使用SynchronizationContext。

    #4楼 2014-10-04 13:02 | 天朝码农  
    还是用最后一个吧

    #5楼 2014-10-04 18:42 | KMSFan  
    来捧场坦克兄的文章

    #6楼[楼主2014-10-04 21:58 | 小坦克  
    @ KMSFan
    多谢捧场

    #7楼 2014-10-05 02:10 | Edison Chou  
    只用过前三种,受教咯,坦克兄给力!

    #8楼 2014-10-05 05:52 | 文楚  
    。。。。建议楼主多看基础东西。
    1、在不禁止检查的时候,winform的控件只能由创建控件的线程去修改,也就是主线程。
    2、要搞清楚,委托的invoke、beginInvoke和控件的invoke、beginInvoke的区别,虽然名字一样但是意义完全不同。
    3、给你一个简单方法:
    在其他线程中只需要写:
    this.beginInvoke(new Action(()=>{
    label2.Text=”aaa”;
    }));
    就可以了。

    #9楼 2014-10-05 05:56 | 文楚  
    忘记说了 上面那个this和你代码中一样是指窗体。

    #10楼 2014-10-05 15:59 | 君霜  
    @ 文楚
    引用 忘记说了 上面那个this和你代码中一样是指窗体。
    @文楚
    引用。。。。建议楼主多看基础东西。
    1、在不禁止检查的时候,winform的控件只能由创建控件的线程去修改,也就是主线程。
    2、要搞清楚,委托的invoke、beginInvoke和控件的invoke、beginInvoke的区别,虽然名字一样但是意义完全不同。
    3、给你一个简单方法:
    在其他线程中只需要写:
    this.beginInvoke(new Action(()=>{
    label2.Text=”aaa”;
    }));
    就可以了。

    控件的 invoke 和 begininvoke 都是调用 主线程 来执行,和一般委托还是不一样的

    #11楼 2014-10-05 16:08 | 君霜  
    个人感觉
    1,UI操作 还是使用 Invoke和BeginInvoke来执行,不容易出错。
    2,不涉及UI的,可以使用后台线程。不过 .net 在没有前台线程运行的时候,会把进程结束掉,导致后台线程也被迫关闭

    #12楼 2014-10-10 09:38 | z5337  
    总结的很不错,比只看代码强

    #13楼 2014-12-22 00:53 | 独孤求败-东方不败  
    @ 洛阳码农

    #14楼 2015-04-29 14:05 | ChuckLu  
    最近发现一个有趣的事情,修改控件的ForeColor不受跨线程访问的影响,但是修改Text的时候就会出错

    #15楼 2016-04-20 17:43 | 苍穹繁星  
    先声明:form 和 class 调用方法不在同一个namespace

    用线程结合Control的invoke、beginInvoke和delegate的invoke、beginInvoke都尝试了,但没用解决这个问题!

    用了最后一种方法解决了界面假死的问题!所以谢谢博主!

    然后,听说可以用注册事件或者代理的方法来解决这个问题,暂时还没做出来,欢迎各位大侠的指导,谢谢!~



    展开全文
  • C#线程调用控件

    2015-10-05 15:27:00
    C#应用程序开发中,我们经常要把UI线程和工作线程分开,防止界面停止响应。同时我们又需要在工作线程中更新UI界面上的控件,下面介绍几种常用的方法 线程间操作无效 界面上有一个button和一个label, 点击...

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

    线程间操作无效

    界面上有一个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)
                {
                    // <span style="color:#ff0000;">当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它</span>
                    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方法是异步的, 它会另起一个线程去完成工作线程

    第四种办法: 使用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(); 
            }

    源代码下载

    请用VS2010打开【下载】

    转自:小坦克

    展开全文
  • C#中利用委托实现多线程跨线程操作 在使用VS2005的时候,如果你从非创建这个控件的线程中访问这个控件或者操作这个控件的话就会抛出这个异常。这是微软为了保证线程安全以及提高代码的效率所做的改进,但是也给大家...
  • c#"] #region ====== invoke ====== //定义一个委托用于跨线程访问方法 delegate void changeLbl(string str, bool bIsAdd); //访问主线程 private void ChangeLbl(string str,bool...
  • c#多线程访问界面

    2012-05-02 21:58:20
    C#2005后不再支持多线程直接访问界面的控件(界面创建线程与访问线程不是同一个线程),不过可以使用delegate来解决: 1. 声明一个delegate和定义一个delegate的实现函数 view plaincopy to clipboardPRint? ...
  • 1、测试调用委托时BeginInvoke和Invoke的表现差异 2、System.Timers.Timer多线程刷新界面 3、System.Threading.ThreadPool多线程刷新界面 4、System.Threading.Thread多线程刷新界面
  • 多线程刷新界面主要用到多线程,委托,线程安全、事件等一系列高难度的C#操作。 1、使用timer控件对要刷新的控件进行定时刷新 对刷新频率要求不高的时候,可以使用该方法。 2、刷新UI控件 在开发软件时经常会...
  • C#多线程界面操作

    2014-01-18 21:56:43
    c# delegate(委托)与多线程很多时候写windows程序都需要结合多线程,在.net中用如下得代码来创建并启动一个新的线程。public void ThreadProc();Thread thread = new Thread( new ThreadStart( ThreadProc ) );...
  • 本项目使用VS2008平台的C#语言使用多线程操作,并在线程中实现了对主线程控件的使用。
  • 1调用界面控件之前,检测当前线程是否和界面线程相同, 2如果不同,启用BeginInvoke委托调用方法解决异常 #region 委托显示 delegate void DisplayCallback(object displayer); public void ShowMsgCallback(o.....
  • C#多线程|匿名委托传参数|测试您的网站能承受的压力|附源代码--升级版 为了让程序执行中不出现界面卡死的现像,最好的方法就是多线程来解决 一个主线程来创建界面,使用一个子线程来执行程序并更新主界面 这样就...
  • 在窗体的多线程环境下可能出现某个线程循环或者死循环的情况下,窗体或控件出现假死不刷新状态。大多数这种情况可以使用以下方法解决: Application.DoEvents(); 示例: //某个导致界面假死的循环 while (true)...
  • 从上面你可能已经看出如何多线程操作同一个控件的,就是通过一个委托,然后定义委托方法,判断控件的InvokeRequired属性(这个属性的元数据讲的很到位,“因为调用方位于创建控件所在的线程以外的线程中”,很清楚)...
1 2 3 4 5 ... 20
收藏数 20,764
精华内容 8,305