在UI线程中从异步组件触发事件我正在.Net2.0中构建一个非可视化组件。该组件使用异步套接字(BeginReceive、EndReceive等)。异步回调在运行时创建的工作线程的上下文中调用。组件用户不必担心多线程(这是主要目标,我想要的)组件用户可以在任何线程中创建我的非可视化组件(UI线程只是简单应用程序的通用线程。更严肃的应用程序可以工作在任意线程中创建组件)。组件触发诸如“SessionConnected”或“DataAvailable”之类的事件。问题:由于异步回调和其中引发的事件,事件处理程序在工作线程上下文中执行。我想使用一个中介来强制事件处理程序在首先创建组件的线程的上下文中执行。示例代码(从异常处理等中删除...)//////连接结束时发生//////IAsyncResult从privatevoidEndConnect(IAsyncResultar){//传递连接状态使用事件this.Socket.EndConnect(ar);this.Stream=newNetworkStream(this.Socket);//--在这里触发连接事件--//设置接收回调this.Receive();}//////数据接收完成时发生;当收到0个字节时,我们可以假设连接已关闭,因此我们应该断开连接//////BeginRead使用的IAsyncResultprivatevoidEndReceive(IAsyncResultar){intnBytes;nBytes=this.Stream.EndRead(ar);if(nBytes>0){//--在这里触发接收数据事件--//设置下一个接收回调if(this.Connected)this.Receive();}else{this.Disconnect();由于异步套接字的性质,所有使用我的组件的应用程序都充斥着“If(this.InvokeRequired){...”,我想要的只是让用户能够将我的组件用作插件。那么,如何在不要求用户检查InvokeRequired的情况下引发事件(或者换句话说,如何强制在与首先引发事件的线程相同的线程中引发事件)?我读过有关AsyncOperation、BackgroundWorkers、SynchronizingObjects、AsyncCallbacks和大量其他内容的信息,但这一切都让我头晕目眩。我确实想出了这个笨拙的“解决方案”,但它在某些情况下似乎失败了(例如,当我通过静态类从WinForms项目调用我的组件时)//////引发事件,确保BeginInvoke为需要调用的控件调用////////////http://www.eggheadcafe.com/articles/20060727.aspprotectedvoidRaiseEvent(DelegateeventDelegate,object[]args){if(eventDelegate!=null){try{Controled=eventDelegate.TargetasControl;如果((ed!=null)&&(ed.InvokeRequired))ed.Invoke(eventDelegate,args);elseeventDelegate.DynamicInvoke(args);}catch(Exceptionex){Console.WriteLine(ex.GetType());Console.WriteLine(ex.Message);//Swallow}}}任何帮助将不胜感激。提前致谢!编辑:根据这个线程,我最好的选择是使用SyncrhonizationContext.Post,但我看不出如何将它应用到我的情况。好的;所以这就是我在阅读后得出的结论:publicclassMyComponent{privateAsyncOperation_asyncOperation;///我的组件的构造函数:MyComponent(){_asyncOperation=AsyncOperationManager.CreateOperation(null);}//////引发事件,确保上下文正确/////////protectedvoidRaiseEvent(DelegateeventDelegate,object[]args){if(eventDelegate!=null){_asyncOperation.Post(newSystem.Threading.SendOrPostCallback(delegate(objectargobj){eventDelegate.DynamicInvoke(argobjasobject[]);}),args);}}}此处发布的另一个解决方案正在进行中。此处发布的解决方案(根据MSDN)似乎是迄今为止最好的解决方案。非常欢迎提出建议。我似乎找到了我的解决方案:privateSynchronizationContext_currentcontext///我的组件的构造函数:MyComponent(){_currentcontext=WindowsFormsSynchronizationContext.Current;//...或者...?_currentcontext=SynchronizationContext.Current;}//////引发事件,确保上下文正确/////////protectedvoidRaiseEvent(DelegateeventDelegate,object[]args){if(eventDelegate!=null){if(_currentcontext!=空)_currentcontext。Post(newSystem.Threading.SendOrPostCallback(delegate(objecta){eventDelegate.DynamicInvoke(aasobject[]);}),args);否则eventDelegate.DynamicInvoke(args);我仍在测试这个,但它似乎工作正常。也许我不明白这个问题,但在我看来,您可以在异步状态下传递对自定义对象的引用。我将以下示例放在一起进行说明;首先我们有一个回调对象。这有2个属性-一个用于调度动作的控件和一个要调用的动作;公共类回调{公共控制控制{得到;放;}公共操作方法{get;放;然后我有一个WinForms项目,在另一个线程上调用一些随机代码(使用BeginInvoke),然后在代码执行完成时显示一个消息框。privatevoidForm1_Load(objectsender,EventArgse){Actionact=(boolmyBool)=>{Thread.Sleep(5000);};act.BeginInvoke(true,newAsyncCallback((IAsyncResultresult)=>{Callbackc=result.AsyncStateasCallback;c.Control.Invoke(c.Method);}),newCallback(){Control=this,Method=()=>{ShowMessageBox();}});ShowMessageBox方法必须在UI线程中像这样运行它:privatevoidShowMessageBox(){MessageBox.Show("Testing");}这是你想要的?如果您的组件必须始终由同一个线程使用,您可以这样做:publicdelegatevoidCallbackInvoker(Delegatemethod,paramsobject[]args);publicYourComponent(CallbackInvokerinvoker){m_invoker=invoker;}protectedvoidRaiseEvent(DelegateeventDelegate,object[]args){if(eventDelegate!=null){try{if(m_invoker!=null)m_invoker(eventDelegate,args);否则eventDelegate.DynamicInvoke(args);}catch(Exceptionex){Console.WriteLine(ex.GetType());Console.WriteLine(ex.Message);//Swallow}}}然后,当您从窗体或其他控件实例化您的组件时,您可以:组件c=newYourComponent(this.Invoke);要在非UI工作线程上排队事件,它必须有某种工作排队机制,那么你可以提供带有CallbackInvoker签名的方法来在工作线程上排队委托以上方法是C#学习教程:所有分享的内容来自UI线程中异步组件的Fire事件。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。代表立场,如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
