来自UI线程中的Async组件的Fire事件

Com*_*der 7 c# sockets user-interface asynchronous invokerequired

我正在.Net 2.0中构建一个非可视组件.该组件使用异步套接字(BeginReceive,EndReceive等).异步回调在运行时创建的工作线程的上下文中调用.组件用户不必担心多线程(这是主要目标,我想要的)

组件用户可以在任何线程中创建我的非可视组件(UI线程只是简单应用程序的通用线程.更严重的应用程序可以在任意工作线程中创建组件).组件触发事件,例如"SessionConnected"或"DataAvailable".

问题:由于Async Callbacks和其中引发的事件,事件处理程序在工作线程上下文中执行.我想使用一个中间层,它强制事件处理程序在首先创建组件的线程的上下文中执行.

示例代码(从异常处理等中删除...)

    /// <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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

由于Async套接字的性质,使用我的组件的所有应用程序都充斥着"If(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
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激.提前致谢!

编辑:根据这个线程,我最好的选择是使用SyncrhonizationContext.Post,但我看不到如何将它应用于我的情况.

Com*_*der 2

好的; 所以这就是我在阅读更多内容后得到的结果:

public class MyComponent {
    private AsyncOperation _asyncOperation;

    /// Constructor of my component:
    MyComponent() {
        _asyncOperation = AsyncOperationManager.CreateOperation(null);
    }

    /// <summary>
    /// Raises an event, ensuring the correct context
    /// </summary>
    /// <param name="eventDelegate"></param>
    /// <param name="args"></param>
    protected void RaiseEvent(Delegate eventDelegate, object[] args)
    {
        if (eventDelegate != null)
        {
            _asyncOperation.Post(new System.Threading.SendOrPostCallback(
                delegate(object argobj)
                {
                    eventDelegate.DynamicInvoke(argobj as object[]);
                }), args);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

此处发布的另一个解决方案是一种正在进行中的解决方案。这里发布的解决方案似乎(根据 MSDN)是迄今为止最好的。非常非常欢迎提出建议。