c# Winform 多线程操作

主要是对一个过程需要的时间很长执行时会出现界面假死的情况

方法1:

Application.DoEvents(),这种方法当你拖动窗体时,界面不会假死。但在你拖动时代码不再执行,也就是阻塞了,当你不再控制窗体时会继续执行,其实这还是一个单线程

  for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 100000; j++)
                {

                    textBox1.Text = i.ToString() + " " + j.ToString();
                    Application.DoEvents();
                }
            }

 

方法2:多线程

       2.1:取消控件跨线程检测(不推荐有时会出现一些莫名奇妙的错误如控件不能加载等问题

               2.1.1取消窗体内控件的跨线程检查(单个控件取消也可以)    

        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;//干掉检测 不再检测跨线程
        }

               2.1.2新建线程实现跨线程访问

        /// <summary>
        /// 新建线程并执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 
            Thread thread = new Thread(thStart);
            thread.Priority = ThreadPriority.Highest;
            thread.IsBackground = true; //关闭窗体继续执行
            thread.Start();

        }



        public void Pro()
        {

            for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 100000; j++)
                {                   
                        textBox1.Text = j.ToString();
                }
            }
        }

 

       2.2:主线程中操作(推荐)

    2.2.1 不用取消跨线程访问

        /// <summary>
        /// 新建线程并执行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 
            Thread thread = new Thread(thStart);
            thread.Priority = ThreadPriority.Highest;
            thread.IsBackground = true; //关闭窗体继续执行
            thread.Start();
        }

        public void Pro()
        {
            for (int i = 0; i < 10000; i++)
            {
                for (int j = 0; j < 100000; j++)
                {
                    if (textBox1.InvokeRequired)//不同线程访问了
                        textBox1.Invoke(new Action<TextBox, string>(SetTxtValue), textBox1, j.ToString());//跨线程了
                    else//同线程直接赋值
                        textBox1.Text = j.ToString();
                }
            }
        }

        private void SetTxtValue(TextBox txt, string value)
        {
            txt.Text = value;
        }

 注:多个线程同时访问一个方法时 需要锁定

        public static readonly object obj = new object();
        public void Pro()
        {
            //lock(obj){}=Monitor.Enter(obj)  Monitor.Exit(obj)
            lock (obj)
            {
                for (int i = 0; i < 10000; i++)
                {
                    for (int j = 0; j < 100000; j++)
                    {
                        if (textBox1.InvokeRequired)//不同线程访问了
                            textBox1.Invoke(new Action<TextBox, string>(SetTxtValue), 
                      textBox1, j.ToString());//跨线程了 else//同线程直接赋值 textBox1.Text = j.ToString(); } } } }

 

3.窗体与自定义类之间的多线程操作(适用数据量大查询速度慢时 让数据在新线程中查询 防主线程卡死

     3.1自定义类中定义事件,并定义各事件执行的步骤方法

     3.2窗体中实现类,并生成类各事件,在多线程中执行自定义类的步骤方法

     3.3 代码3.1

public class WeiTuo
    {
        public int count { get; set; }
        public event EventHandler StartEvent;
        public event EventHandler MidEvent;
        public event EventHandler EndEvent;
        public event EventHandler EEvent;


        public void ExecEvent()
        {
            try
            {

                using (SqlConnection con = new SqlConnection("server=.;uid=sa;pwd=123;database=oa"))
                {
                    using (SqlDataAdapter adp = new SqlDataAdapter("select * from a", con))
                    {

                        DataTable dt = new DataTable();
                        adp.Fill(dt);


                        StartEvent(dt.Rows.Count, null);
                        for (int i = 0; i < dt.Rows.Count; i++)
                        {
                            a ai = new a() {
                                ID = (int)dt.Rows[i]["id"],
                                Code = dt.Rows[i]["cCode"].ToString()
                            } ;
                            MidEvent(ai, null);
                        }
                        EndEvent(dt.Rows.Count, null);


                    }
                }
            }
            catch (Exception e)
            {
                EEvent(e.Message, null);

            }
        }
    }


    public class a
    {
        public int ID { get; set; }
        public String Code { get; set; } = "";
    }
View Code

    3.4 代码3.2

private void button6_Click(object sender, EventArgs e)
        {

            WeiTuo wt = new WeiTuo();
            wt.StartEvent += Wt_StartEvent;
            wt.MidEvent += Wt_MidEvent;
            wt.EndEvent += Wt_EndEvent;
            wt.EEvent += Wt_EEvent;

            Thread th = new Thread(wt.ExecEvent);
            th.Start();


        }

        //特殊委托 action
        private void Wt_StartEvent(object sender, EventArgs e)
        {
            Action<string> setLVItem = (s) => { listView1.Items.Add(s); };
            this.Invoke(setLVItem, sender.ToString());

        }
        //特殊委托 action
        private void Wt_MidEvent(object sender, EventArgs e)
        {
            Action<string> setLVItem = (s) => { listView1.Items.Add(s); };
            this.Invoke(setLVItem, ((a)sender).Code);

        }

        #region 委托实现
        private void Wt_EndEvent(object sender, EventArgs e)
        {
            this.Invoke(new setLVItem(setEndValue), "成功");
        }

        delegate void setLVItem(string s);

        void setEndValue(string s)
        {
            MessageBox.Show(s);
        }
        #endregion

        private void Wt_EEvent(object sender, EventArgs e)
        {
            Action<string> ShowBox = (s) => { MessageBox.Show(s); };
            this.Invoke(ShowBox, sender.ToString());

        }
View Code

   3.5 结果如下图

 

task任务与thread大同小异

使用时 尽量少的让控件跨线程 可通过ref 或 out 对参数传出 检测线程结束 再给控件赋值 

也可用task的wait方法

4 异步回调

 private void button1_Click(object sender, EventArgs e)
        {

            Func<int, int, int> Sum = (i, j) =>
            {
                Thread.Sleep(3000);
                return i + j;
            };

            listView1.Items.Add("开始");

            IAsyncResult iar = Sum.BeginInvoke(1, 2, CallbackWhenDone, "我是测试");

            listView1.Items.Add("over");

        }

        private void CallbackWhenDone(IAsyncResult iar)
        {
            AsyncResult ar = (AsyncResult)iar;
            Func<int, int, int> f = (Func<int, int, int>)ar.AsyncDelegate;

            Action<ListView> a = (lv) =>
            {
                lv.Items.Add(ar.AsyncState.ToString());
                lv.Items.Add(f.EndInvoke(iar).ToString());
            };

          this.Invoke( a,listView1);
        }
View Code

 

posted @ 2018-09-15 14:54  伪装大牛  阅读(28163)  评论(0编辑  收藏  举报