zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    流程控制引擎组件化
    (七):C++分布式实时应用框架 2.0
    (六):大型项目容器化改造
    (五):C++分布式实时应用框架——微服务架构的演进
    (四):C++分布式实时应用框架——状态中心模块
    (三):C++分布式实时应用框架——系统管理模块
    (二): 基于ZeroMQ的实时通讯平台
    (一):C++分布式实时应用框架----整体介绍
    分布式压测系列之Jmeter4.0第一季
    选择 NoSQL 需要考虑的 10 个问题
  • 原文地址:https://www.cnblogs.com/SoftWareIe/p/9650947.html
Copyright © 2011-2022 走看看