星期五, 10月 05, 2007

跨執行緒作業無效

Problem:跨執行緒作業無效: 存取控制項 'form2' 時所使用的執行緒與建立控制項的執行緒不同

Answer:
private void ThreadTask()
{
//form2.Visible = true; //出現所使用的執行緒與建立控制項的執行緒不同
ShowForm(); //改用ShowForm()即可
}

private void ShowForm()
{
if (form2.InvokeRequired)
form2.Invoke(new MethodInvoker(ShowForm)); //此ShowForm為delgete型態,即傳Method Name
else
form2.Visible = true;
}

*如果要傳值的話...
以傳string為例,先自行定義delegate
delegate void mydel(string str);
...

//呼叫ShowForm()+傳值
ShowForm("oh ya~")

private void ShowForm(string str)
{

if form2.InvokeRequired)
this.Invoke(new mydel(ShowForm), new object[] { str});
else
this.title =(string)obj[0];
}

注意:如果傳的值是物件的話,得clone新的物件
例:上例

delegate void mydel(Object [] args);
...
//呼叫ShowForm()+傳值
ShowForm( new Object[1])
private void ShowForm(Object [] args)
{
if (this.InvokeRequired)
this.Invoke(a, args.clone()); //clone一個新的
...
}


*較簡單的方法 (轉)

在form_load時加一行
ListBox.CheckForIllegalCrossThreadCalls = False
這樣就會關閉所有listbox的檢查是否為不合法的跨執行緒存取
從vs2005開始, 所有windows form控制項, 都多了一個[能否任意跨執行緒變更屬性]的靜態屬性
這是為了防止控制項在多執行緒情況下工作時, 同時有多個執行緒存取單一控制項, 導致程式發生死結
所以如果要跨執行緒存取控制項, 必須使用Control.Invoke的方法, 來變更控制項目前的屬性,
如果覺得這樣做太麻煩, 而且您自己確定, 不會發生死結

1 則留言:

fishjerky 提到...
作者已經移除這則留言。