跨线程边界进行过程调用 Windows 窗体控件仅可在创建它们的线程上执行,即它们不是线程安全的。如果要从后台线程获取或设置控件的属性或对控件调用方法,则必须将调用封送到创建该控件的线程。在控件上有五个函数对于从任何线程调用都是安全的:InvokeRequired、Invoke、BeginInvoke、 EndInvoke 和 CreateGraphics。对于所有其他方法调用,应使用上述调用方法之一。默认情况下,Windows 为您封送调用。但是,如果对某控件进行多次调用,则您自己创建一个执行这些调用的方法并且进行跨线程调用将有效得多。通过调用 Control.Invoke 方法之一进行跨线程调用。Invoke 方法采用对委托的引用。通常,此委托是 MethodInvoker 委托的一个实例。InvokeRequired public bool InvokeRequired { get ; }如果调用方对此控件进行方法调用时必须调用 Invoke,则返回真。
BeginInvoke public IAsyncResult BeginInvoke(Delegate method) public IAsyncResult BeginInvoke(Delegate method, Object[] args)在拥有此控件的基础窗口句柄的线程上执行给定的委托。异步调用该委托并且该方法立即返回。可从任何线程调用此方法,甚至可以从拥有该控件的句柄的线程上调用。如果该控件的句柄尚不存在,将沿该控件的父链向上查找,直到找到确实有窗口句柄的控件或窗体。如果无法找到相应的句柄,BeginInvoke 将引发异常。此委托方法中的异常被视为未捕获的异常,将发送给应用程序的未捕获的异常处理程序。
EndInvoke public Object EndInvoke(IAsyncResult asyncResult) 检索由传递的 IAsyncResult 接口所代表的异步操作的返回值。如果尚未完成异步操作,此函数将阻塞,直至结果可用。
Invoke public Object Invoke(Delegate method) public Object Invoke(Delegate method, Object[] args) 在拥有此控件的基础窗口句柄的线程上执行给定的委托。同步调用该委托并且此方法在调用的方法返回后立即返回。返回值是调用的方法的结果。在控件所属的同一个线程上调用此方法是错误的。
下面的示例演示如何创建一个后台线程,该线程使用 MethodInvoker 以固定时间间隔更新 ProgressBar 控件: .... //Start the background thread timerThread = new Thread(new ThreadStart(ThreadProc)); timerThread.IsBackground = true; timerThread.Start(); .... //This function is executed on a background thread - it marshalls calls to //update the UI back to the foreground thread public void ThreadProc() { try { MethodInvoker mi = new MethodInvoker(this.UpdateProgress); while (true) { //Call BeginInvoke on the Form this.BeginInvoke(mi); Thread.Sleep(500) ; } } //Thrown when the thread is interupted by the main thread - exiting the loop catch (ThreadInterruptedException e) { //Simply exit.... } catch (Exception we) { } } .... //This function is called from the background thread private void UpdateProgress() { //Reset to start if required if (progressBar1.Value == progressBar1.Maximum) { progressBar1.Value = progressBar1.Minimum ; } //Reset to start if required progressBar1.PerformStep() ; } .... //Make sure we clean up the background thread in Dispose public override void Dispose() { if (timerThread != null) { timerThread.Interrupt(); timerThread = null; } base.Dispose(); } .... ' Start the background thread timerThread = new Thread(new ThreadStart(AddressOf ThreadProc)) timerThread.IsBackground = True timerThread.Start() .... ' This function is executed on a background thread - it marshalls calls to ' update the UI back to the foreground thread Public Sub ThreadProc() Try Dim mi As New MethodInvoker(AddressOf Me.UpdateProgress) Do While True ' Call BeginInvoke on the Form Me.BeginInvoke(mi) Thread.Sleep(500) Loop ' Thrown when the thread is interupted by the main thread - exiting the loop Catch e As ThreadInterruptedException ' Simply exit.... Catch we As Exception End Try End Sub .... ' This function is called from the background thread Private Sub UpdateProgress() ' Reset to start if required If progressBar1.Value = progressBar1.Maximum progressBar1.Value = progressBar1.Minimum End If ' Reset to start if required progressBar1.PerformStep() End Sub .... ' Make sure we clean up the background thread in Dispose Public Override Sub Dispose() If Not timerThread Is Nothing Then timerThread.Interrupt() timerThread = Nothing End If MyBase.Dispose() End Sub
private void button1_Click(object sender, System.EventArgs e)
{
Thread myThread=new Thread(new ThreadStart(ChangeCaption));
myThread.Start();
}private void change()
{
this.label1.Text = S"Thread is runing";
}private void ChangeCaption()
{
MethodInvoker mi=new MethodInvoker(change);
mi.BeginInvoke(null,null);
}
Windows 窗体控件仅可在创建它们的线程上执行,即它们不是线程安全的。如果要从后台线程获取或设置控件的属性或对控件调用方法,则必须将调用封送到创建该控件的线程。在控件上有五个函数对于从任何线程调用都是安全的:InvokeRequired、Invoke、BeginInvoke、 EndInvoke 和 CreateGraphics。对于所有其他方法调用,应使用上述调用方法之一。默认情况下,Windows 为您封送调用。但是,如果对某控件进行多次调用,则您自己创建一个执行这些调用的方法并且进行跨线程调用将有效得多。通过调用 Control.Invoke 方法之一进行跨线程调用。Invoke 方法采用对委托的引用。通常,此委托是 MethodInvoker 委托的一个实例。InvokeRequired public bool InvokeRequired { get ; }如果调用方对此控件进行方法调用时必须调用 Invoke,则返回真。
BeginInvoke public IAsyncResult BeginInvoke(Delegate method)
public IAsyncResult BeginInvoke(Delegate method, Object[] args)在拥有此控件的基础窗口句柄的线程上执行给定的委托。异步调用该委托并且该方法立即返回。可从任何线程调用此方法,甚至可以从拥有该控件的句柄的线程上调用。如果该控件的句柄尚不存在,将沿该控件的父链向上查找,直到找到确实有窗口句柄的控件或窗体。如果无法找到相应的句柄,BeginInvoke 将引发异常。此委托方法中的异常被视为未捕获的异常,将发送给应用程序的未捕获的异常处理程序。
EndInvoke public Object EndInvoke(IAsyncResult asyncResult)
检索由传递的 IAsyncResult 接口所代表的异步操作的返回值。如果尚未完成异步操作,此函数将阻塞,直至结果可用。
Invoke public Object Invoke(Delegate method)
public Object Invoke(Delegate method, Object[] args)
在拥有此控件的基础窗口句柄的线程上执行给定的委托。同步调用该委托并且此方法在调用的方法返回后立即返回。返回值是调用的方法的结果。在控件所属的同一个线程上调用此方法是错误的。
下面的示例演示如何创建一个后台线程,该线程使用 MethodInvoker 以固定时间间隔更新 ProgressBar 控件: .... //Start the background thread
timerThread = new Thread(new ThreadStart(ThreadProc));
timerThread.IsBackground = true;
timerThread.Start(); .... //This function is executed on a background thread - it marshalls calls to
//update the UI back to the foreground thread
public void ThreadProc() { try {
MethodInvoker mi = new MethodInvoker(this.UpdateProgress);
while (true) { //Call BeginInvoke on the Form
this.BeginInvoke(mi);
Thread.Sleep(500) ;
}
}
//Thrown when the thread is interupted by the main thread - exiting the loop
catch (ThreadInterruptedException e) {
//Simply exit....
}
catch (Exception we) {
}
} .... //This function is called from the background thread
private void UpdateProgress() { //Reset to start if required
if (progressBar1.Value == progressBar1.Maximum) {
progressBar1.Value = progressBar1.Minimum ;
}
//Reset to start if required
progressBar1.PerformStep() ;
} .... //Make sure we clean up the background thread in Dispose
public override void Dispose() {
if (timerThread != null) {
timerThread.Interrupt();
timerThread = null;
} base.Dispose();
}
.... ' Start the background thread
timerThread = new Thread(new ThreadStart(AddressOf ThreadProc))
timerThread.IsBackground = True
timerThread.Start() .... ' This function is executed on a background thread - it marshalls calls to
' update the UI back to the foreground thread
Public Sub ThreadProc() Try
Dim mi As New MethodInvoker(AddressOf Me.UpdateProgress)
Do While True ' Call BeginInvoke on the Form
Me.BeginInvoke(mi)
Thread.Sleep(500)
Loop ' Thrown when the thread is interupted by the main thread - exiting the loop
Catch e As ThreadInterruptedException
' Simply exit.... Catch we As Exception
End Try
End Sub .... ' This function is called from the background thread
Private Sub UpdateProgress() ' Reset to start if required
If progressBar1.Value = progressBar1.Maximum
progressBar1.Value = progressBar1.Minimum
End If
' Reset to start if required
progressBar1.PerformStep()
End Sub .... ' Make sure we clean up the background thread in Dispose
Public Override Sub Dispose()
If Not timerThread Is Nothing Then
timerThread.Interrupt()
timerThread = Nothing
End If MyBase.Dispose()
End Sub