从UI线程异步组件一旦发生火灾 [英] Fire event from Async component in UI thread

查看:146
本文介绍了从UI线程异步组件一旦发生火灾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

该组件用户可以创建我的任何线程非可视化组件(UI线程仅仅是简单的应用程序的共同点。更严重的应用程序可以创建一个任意的工作线程中的组件)。组件触发事件,如SessionConnected或DataAvailable

问题:因为异步回调和其中的事件处理程序的工作线程上下文中执行引发的事件的。我想用迫使中间层
的事件处理程序,其中所创建的线程的上下文中执行
组件按第一的位置。

举例code(从异常处理剥离等)

  ///<总结>
    ///当连接结束时发生
    ///< /总结>
    ///&所述; PARAM NAME =芳>将IAsyncResult的读取来自以下的的信息; /参数>
    私人无效EndConnect(IAsyncResult的AR)
    {
        //使用事件通连接状态
        this.Socket.EndConnect(AR);        this.Stream =新的NetworkStream(this.Socket);        // - 消防相关事件的位置 -         //设置接收回调
        this.Receive();
    }
    ///<总结>
    ///当数据接收完成后进行;当0字节收到我们可以认为连接被关闭,所以我们应该断开
    ///< /总结>
    ///&所述; PARAM NAME =芳>将IAsyncResult的已使用的的BeginRead&所述; /参数>
    私人无效EndReceive(IAsyncResult的AR)
    {
        INT为nbytes;
        为nbytes = this.Stream.EndRead(AR);
        如果(为nbytes大于0)
        {
            // - 消防接收到的数据EVENT这里 -             //设置一个接收回调
            如果(this.Connected)
                this.Receive();
        }
        其他
        {
            this.Disconnect();
        }
    }

由于异步的性质插座使用我的组件的所有应用程序都充满了如果(this.InvokeRequired){...而我要的是用户能够以某种使用我的组件无忧一滴项。

所以,我怎么会去养的事件,而不需要用户检查InvokeRequired(或者,换句话说,我怎么用力在同一个线程作为首先启动了事件的线程引发的事件)<? / p>

我看过的东西有关AsyncOperation,BackgroundWorkers,SynchronizingObjects,AsyncCallbacks和吨其他的东西,但是这一切都让我目瞪口呆。

我也想出这个,肯定笨拙,解决方案,但它似乎在某些情况下会失败(当我的组件从WinForms项目通过例如静态类的称呼)

  ///&LT;总结&gt;
    ///引发一个事件,确保调用BeginInvoke对于需要调用控件
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =eventDelegate&GT;&LT; /参数&GT;
    ///&LT; PARAM NAME =ARGS&GT;&LT; /参数&GT;
    ///&LT;&言论GT; HTTP://www.eggheadcafe.com/articles/20060727.asp< /言论&GT;
    保护无效的RaiseEvent(代表eventDelegate,对象[]参数)
    {
        如果(eventDelegate!= NULL)
        {
            尝试
            {
                控制ED = eventDelegate.Target的控制;
                如果((ED = NULL)及!及(ed.InvokeRequired))
                    ed.Invoke(eventDelegate,参数);
                其他
                    eventDelegate.DynamicInvoke(参数);
            }
            赶上(异常前)
            {
                Console.WriteLine(ex.GetType());
                Console.WriteLine(ex.Message);
                //吞
            }
        }
    }

任何帮助将是AP preciated。在此先感谢!

编辑:
根据这个线程我最好的选择是使用SyncrhonizationContext。邮政但我不能看到如何将其应用到我的情况。


解决方案

确定;所以这里是我结束了一些阅读后:

 公共类MyComponent的{
    私人AsyncOperation _asyncOperation;    ///我的组件的构造函数:
    MyComponent的(){
        _asyncOperation = AsyncOperationManager.CreateOperation(NULL);
    }    ///&LT;总结&gt;
    ///引发一个事件,以确保正确的上下文
    ///&LT; /总结&gt;
    ///&LT; PARAM NAME =eventDelegate&GT;&LT; /参数&GT;
    ///&LT; PARAM NAME =ARGS&GT;&LT; /参数&GT;
    保护无效的RaiseEvent(代表eventDelegate,对象[]参数)
    {
        如果(eventDelegate!= NULL)
        {
            _asyncOperation.Post(新System.Threading.SendOrPostCallback(
                委托(对象argobj)
                {
                    eventDelegate.DynamicInvoke(argobj为对象[]);
                }),参数);
        }
    }
}

其他的解决方案张贴在这里被排序的工作正在进行中。这里发布的解决方案(根据MSDN)是最好的,到目前为止,似乎。建议是非常,非常受欢迎。

I'm building a non-visual component in .Net 2.0. This component uses an asynchronous socket (BeginReceive, EndReceive etc). Asynchronous callbacks are called in the context of a worker thread created by the runtime. The component user shouldn't have to worry about multithreading (This is the main goal, what I want)

The component user can create my non-visual component in any thread (the UI thread is just a common thread for simple applications. More serious applications could create the component within an arbitrary worker thread). The component trigger events such as "SessionConnected" or "DataAvailable".

The issue: because of the Async Callbacks and the events raised therein the event handler is executed in the worker thread context. I want to use an intermediate layer which force the event handler to execute in the context of the thread which created the component at the first place.

Example code (stripped from exception handling etc...)

    /// <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();
        }
    }

Because of the nature of the Async sockets all applications using my component are littered with "If (this.InvokeRequired) { ..." and all I want is the user to be able to use my component worry-free as sort of a drop-in.

So how would I go about raising the events without requiring the user to check InvokeRequired (or, put differently, how do I force the events raised in the same thread as the thread that initiated the event in the first place)?

I have read stuff about AsyncOperation, BackgroundWorkers, SynchronizingObjects, AsyncCallbacks and tons of other stuff but it all makes my head spin.

I did come up with this, surely clumsy, "solution" but it seems to fail in some situations (when my component is called from a WinForms project via a static class for example)

    /// <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
            }
        }
    }

Any help would be appreciated. Thanks in advance!

EDIT: According to this thread my best bet would be to use SyncrhonizationContext.Post but I can't see how to apply it to my situation.

解决方案

Ok; so here's what I ended up with after some more reading:

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);
        }
    }
}

The other solution posted here was sort of a work-in-progress. The solution posted here seems (according to MSDN) be the best so far. Suggestions are very, very welcome.

这篇关于从UI线程异步组件一旦发生火灾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆