我在.Net 2.0中構建了一個非可視化組件。該組件使用異步套接字(BeginReceive,EndReceive等)。異步回調在由運行時創建的工作線程的上下文中調用。組件用戶不必擔心多線程(這是我想要的主要目標)UI線程中的異步組件觸發事件
組件用戶可以在任何線程中創建我的非可視組件(UI線程只是簡單的普通線程應用程序,更嚴重的應用程序可以在任意工作線程中創建組件)。組件觸發事件,如「SessionConnected」或「DataAvailable」。
問題:由於異步回調和其中引發的事件,事件處理程序在工作程序線程上下文中執行。我想使用一箇中間層,它強制事件處理程序在首先創建 組件的線程的上下文中執行。
示例代碼(從異常處理等剝離...)
/// <summary>
/// Occurs when the connection is ended
/// </summary>
/// <param name="ar">The IAsyncResult to read the information from</param>
private void EndConnect(IAsyncResult ar)
{
// pass connection status with event
this.Socket.EndConnect(ar);
this.Stream = new NetworkStream(this.Socket);
// -- FIRE CONNECTED EVENT HERE --
// Setup Receive Callback
this.Receive();
}
/// <summary>
/// Occurs when data receive is done; when 0 bytes were received we can assume the connection was closed so we should disconnect
/// </summary>
/// <param name="ar">The IAsyncResult that was used by BeginRead</param>
private void EndReceive(IAsyncResult ar)
{
int nBytes;
nBytes = this.Stream.EndRead(ar);
if (nBytes > 0)
{
// -- FIRE RECEIVED DATA EVENT HERE --
// Setup next Receive Callback
if (this.Connected)
this.Receive();
}
else
{
this.Disconnect();
}
}
由於異步性質的插座使用我的組件的所有應用程序與散落「如果(this.InvokeRequired){... 「而我所需要的就是用戶能夠無憂無慮地使用我的組件作爲一種插件。
因此,如何在不需要用戶檢查InvokeRequired的情況下提升事件(或者換句話說,我如何強制與首先發起事件的線程在同一線程中引發的事件)?
我讀過關於AsyncOperation,BackgroundWorkers,SynchronizingObjects,AsyncCallbacks和其他東西的東西,但這一切都讓我頭暈目眩。
我沒有想出這個,想必笨拙,「解決方案」,但它似乎在某些情況下會失敗(當我的組件從WinForms項目經由例如靜態類的稱呼)
/// <summary>
/// Raises an event, ensuring BeginInvoke is called for controls that require invoke
/// </summary>
/// <param name="eventDelegate"></param>
/// <param name="args"></param>
/// <remarks>http://www.eggheadcafe.com/articles/20060727.asp</remarks>
protected void RaiseEvent(Delegate eventDelegate, object[] args)
{
if (eventDelegate != null)
{
try
{
Control ed = eventDelegate.Target as Control;
if ((ed != null) && (ed.InvokeRequired))
ed.Invoke(eventDelegate, args);
else
eventDelegate.DynamicInvoke(args);
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType());
Console.WriteLine(ex.Message);
//Swallow
}
}
}
任何幫助將不勝感激。提前致謝!
編輯: 根據this thread我最好的選擇是使用SyncrhonizationContext.Post,但我不明白如何將它應用於我的情況。
不是真的;這是使用我的組件時複雜的方法。所有的操作都是引用組件並使用如下代碼: //用IP,端口等初始化MyComponent然後: MyComponent.SendString(「This is cool」); MyComponent引發事件;不管它們是由GUI還是非GUI項目處理都無關緊要,我不希望用戶負責檢查InvokeRequired。 – ComponentBuilder 2010-01-07 17:45:08