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