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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM