C# 线程thread

一、问题总结

 1. 在WinForm开发过程中用到线程时,往往需要在线程中访问线程外的控件,比如:设置textbox的Text值等等。如果直接访问UI控件会报出“从不是创建控件的线程访问它”错误。控件是在主线程中创建的(比如this.Controls.Add(...);),在其它线程直接访问主线程控件,与主线程发生线程冲突。

解决方法:

在控件响应函数中调用控件的Invoke方法,Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。

MSDN中说:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。
Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性 。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。   

2. invoke表示同步,begininvoke表示异步。

3.在使用invoke前,判断IsHandleCreated 此属性指示控件是否有与他关联的句柄,如果已经为控件分配了句柄,则为 true;否则为 false。

 加此判断可以避免在退出程序的时候,如果此时调用了invoke中的控件,就会出现错误“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”

二、代码举例

 1.线程访问主线程控件  

using System;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {

        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(new ThreadStart(DoWork));
            th.Start();         

        }     
        private void DoWork()
        {          
            ShowMsg("hello world");           
        }

        delegate void ShowMsgDelegate(string msg); 
        //普通委托
        private void ShowMsg(string msg)
        {
            if(lblMsg.InvokeRequired)
            {
                ShowMsgDelegate showMsgDelegate = new ShowMsgDelegate(ShowMsg);
                lblMsg.Invoke(showMsgDelegate, new object[] { msg });
            }
            else
            {
                lblMsg.Text = msg;
            }           

        }

        //匿名代理
        private void ShowMsg2(string msg)
        {
            ShowMsgDelegate showMsgDelegate = delegate (string str)
            {
                lblMsg.Text = str;
            };
            lblMsg.Invoke(showMsgDelegate, new object[] { msg });

        }

        //在C# 3.0及以后的版本中有了Lamda表达式,
        //像上面这种匿名委托有了更简洁的写法。
        private void ShowMsg3(string msg)
        {
            this.Invoke(new Action(() => {
                lblMsg.Text = msg;
            }
            ));
        }

       
    }
}

 

private void ShowMsg(string msg, bool isOk)
{
    if (this.IsHandleCreated)
    {
        this.Invoke(new Action(() =>
        {
            lblMsg.Text = msg;
            lblMsg.ForeColor = isOk ? Color.Green : Color.Red;

        }));
    }
}

 

 

 

lambda写法

  private void button1_Click(object sender, EventArgs e)
        {
            Console.WriteLine("start");
            testThread =new Thread(() =>{

                for(int i=0;i<20;i++)
                {
                    Console.WriteLine(i);
                }
               
            });
            testThread.Start();
            Console.WriteLine("end");
        }

执行结果:

start
end
0
1
2
3
4
5
6
7
8
9

posted @ 2019-08-09 15:38  ike_li  阅读(400)  评论(0编辑  收藏  举报