2009年3月5日 星期四

在不同執行緒下存取UI控制項(textbox combobox)

問題描述 :在不同執行緒下呼叫方法,方法裡面需要存取主執行緒下的UI控制項

解法:

1.Form.CheckForIllegalCrossThreadCalls = False

2.建立委派

3.使用BackgroundWorker


這裡介紹第二種

首先在windows.form 的 onload事件建置一條執行緒

compareandprintout = new Thread(new ThreadStart(MRTcompareThread));
compareandprintout.Start();

這條thread 會執行compare()方法,存取UI控制項的程式就寫在裡面(存取textbox,combobox)
public void MRTcompareThread()
{
compare(); //裡面有無限迴圈
}

委派的建立!!


1.建立方法

publik int XXmethod(int a, int b);

2.宣告委派;委派參數,需要與被呼叫的方法一樣,包含回傳型別 (相同 signature)

   private delegate void XXDelegate();
   private delegate int XXDelegate(int a, int b);

3.引用委派(實體化),後指定方法

XXDelegate d = new XXDelegate(XXMethod); //參考的方法只要名稱就可以了
4.呼叫函數

invoke();


真的開始囉~~

於class form1裡宣告委派

delegate void SetTextCallback(Control ctl,String str); 設置textbox.text
delegate string GetTextCallback(Control ctl); 讀取textbox.text
delegate string GetCBTextCallback(ComboBox ctl, int i); 讀取ComboBox
delegate string GetCBTextCallback(Listcontrol ctl, int i); 讀取ComboBox


另外要寫委派方法
public string gettext(Control ctl)
{
if (this.InvokeRequired) //InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true.
{

GetTextCallback d = new GetTextCallback(gettext);
// this.Invoke(d);
string x;
x =(string) this.Invoke(d, new Object[] { ctl });
return x;
}
else
{
return ctl.Text;
}

}
public void settext(Control ctl,String str)
{
if (this.InvokeRequired)
{
SetTextCallback s = new SetTextCallback(settext);
this.Invoke(s, ctl, str );
}
else
{
ctl.Text = str;
}
}
public string getCBtext(ComboBox ctl, int i)
{
if (this.InvokeRequired)
{
string try1 = ctl.GetItemText(i); //i = 1 2 3 4 遞增,奇怪~難道我誤會MSDN? 給出來的是combobox的item索引
string try2 = (string)ctl.Items[i];//

GetCBTextCallback Gcb = new GetCBTextCallback(getCBtext); //建立
string x;
x = (string)this.Invoke(Gcb, ctl, i);
return x;
}
else
{
return (string) ctl.Items[i];
// return ctl.GetItemText(i);
}
}


在非產生UI控制項的副執行緒主程式 compare裡面有

while(true)
{
for (i = 1; i < style="color: rgb(51, 204, 255);"> getCBtext(comboBox1,i) && startstation == true)
//if (nowBox.Text == comboBox1.Items[i].ToString() )
{
//onBox.Text = comboBox1.Items[i].ToString(); //debug會出錯(不同控制項執行緒叫用 ... 我忘了)
string y = getCBtext(comboBox1,i) ;
settext(onBox, y); //叫用方法,自動判斷叫用invoke

}
}

for (i = 1; i < style="color: rgb(255, 0, 0);">// if (onBox.Text == comboBox1.Items[i].ToString())
{
if (goal > getonposition)
{
//nexterrorstop = comboBox1.Items[i - 1].ToString();
nexterrorstop = getCBtext(comboBox1,i-1);
}
else
{
nexterrorstop = "error";
}
}
}



}


VB版
一樣 ,先建立一個拿來更新 UI 的方法( UpdateUI),再建立一個有相同 signature 的委派( UpdateUICallBack)

Private Delegate Sub UpdateUICallBack(ByVal newText As String, ByVal c As Control)

Private Sub UpdateUI(ByVal newText As String, ByVal c As Control)
If Me.InvokeRequired() Then
Dim cb As New UpdateUICallBack(AddressOf UpdateUI)
Me.Invoke(cb, newText, c)
Else
c.Text = newText
End If
End Sub


ref:

舊文重發:Windows 表單與多執行緒


HOW TO:進行對 Windows Form 控制項的安全執行緒呼叫

VB/ VBA/ C#/ Java/ C++ 語言學習筆記

沒有留言:

張貼留言

try comments