C#线程间操作无效: 从不是创建控件 XX 的线程访问它
轉(zhuǎn)自:http://www.arasplm.net/index.php/zh/community/myblog/c-xx-.html
前些天做的要使用到線程的項(xiàng)目,現(xiàn)在和大家分享一下感受!
以下面小列子為例,給出這個(gè)問題的解決辦法。下面的列子是以一個(gè)計(jì)數(shù)器為列講解的。
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
// 創(chuàng)建線程
Thread newThread = new Thread(new ThreadStart(Count)); newThread.Start();
}
public void Count()
{
for (int i = 0; i < 100; i++)
{
lblCount.Text = i.ToString();//此時(shí)就會(huì)報(bào)出“線程間操作無效: 從不是創(chuàng)建控件" lblCount" 的線程訪問它”;
Thread.Sleep(1000);
}
}
?
解決辦法一:設(shè)置 Control.CheckForIllegalCrossThreadCalls = false;
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
// 方法一 獲取或設(shè)置一個(gè)值,該值指示是否捕獲對(duì)錯(cuò)誤線程的調(diào)用,這些調(diào)用在調(diào)試應(yīng)用程序時(shí)訪問控件的 Handle 屬性 // Control.CheckForIllegalCrossThreadCalls = false;
// 創(chuàng)建線程
Thread newThread = new Thread(new ThreadStart(Count)); newThread.Start();
}
public void Count()
{
for (int i = 0; i < 100; i++)
{
lblCount.Text = i.ToString();
Thread.Sleep(1000);
}
}
解決辦法二:使用Invoke方法
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
//Invoke方法是同步的方法,所以執(zhí)行過程是有先后順序的,所以就不會(huì)出現(xiàn)那個(gè)異常了
//創(chuàng)建線程
Thread newThread = new Thread(new ThreadStart(Count));
//加上這句話,否則在關(guān)閉窗體時(shí)會(huì)出現(xiàn)如下錯(cuò)誤:在創(chuàng)建窗口句柄之前,不能在控件上調(diào)用 Invoke 或 BeginInvoke。
newThread.IsBackground = true;
newThread.Start();
}
public void Count()
{
for (int i = 0; i < 100; i++)
{
this.Invoke((EventHandler)(delegate
{
lblCount.Text = i.ToString(); }));
//這個(gè)不能放在Invoke里面,不然又Form1窗體假死情況
Thread.Sleep(1000);
}
}
解決方法三:通過BeginInvoke方法和委托來實(shí)現(xiàn)
public Form1()
{
InitializeComponent();
}
private void btnStart_Click(object sender, EventArgs e)
{
mydelegate = new myDelegate(ShowMessage); Thread newThread = new Thread(Count);
//加上這句話,否則在關(guān)閉窗體時(shí)會(huì)出現(xiàn)如下錯(cuò)誤:在創(chuàng)建窗口句柄之前,不能在控件上調(diào)用 Invoke 或 BeginInvoke。
newThread.IsBackground = true;
newThread.Start();
}
public void Count()
{
for (int i = 0; i < 100; i++)
{ Thread.Sleep(1000);
this.BeginInvoke(mydelegate, new object[] { i });
}
}
public void ShowMessage(int i)
{
lblCount.Text = i.ToString();
}
以上總結(jié):
因?yàn)榈谝环N方法只是簡(jiǎn)單的將錯(cuò)誤提示禁用了,仍然存在跨線程調(diào)用控件的問題。為此可能造成兩個(gè)線程同時(shí)或者循環(huán)改變?cè)摽丶臓顟B(tài)導(dǎo)致線程死鎖。 Invoke方法是同步的方法,所以執(zhí)行過程是有先后順序的,所以就不會(huì)出現(xiàn)那個(gè)異常了。而第三種方法只是第二種方法的另一種形式而已,在多線程編程中,我們經(jīng)常要在工作線程中去更新界面顯示,而在多線程中直接調(diào)用界面控件的方法是錯(cuò)誤的做法,Invoke 和 BeginInvoke 就是為了解決這個(gè)問題而出現(xiàn)的,使你在多線程中安全的更新界面顯示。
正確的做法是將工作線程中涉及更新界面的代碼封裝為一個(gè)方法,通過 Invoke 或者 BeginInvoke 去調(diào)用,兩者的區(qū)別就是一個(gè)導(dǎo)致工作線程等待,而另外一個(gè)則不會(huì)。
轉(zhuǎn)載于:https://www.cnblogs.com/Jezze/archive/2012/08/30/2663447.html
總結(jié)
以上是生活随笔為你收集整理的C#线程间操作无效: 从不是创建控件 XX 的线程访问它的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 米面粉怎么做好吃啊?
- 下一篇: treeview 保持选中状态