Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从UI线程中的异步组件触发事件_C#_User Interface_Asynchronous_Sockets_Invokerequired - Fatal编程技术网

C# 从UI线程中的异步组件触发事件

C# 从UI线程中的异步组件触发事件,c#,user-interface,asynchronous,sockets,invokerequired,C#,User Interface,Asynchronous,Sockets,Invokerequired,我正在.NET2.0中构建一个非可视组件。此组件使用异步套接字(BeginReceive、EndReceive等)。异步回调是在运行时创建的工作线程的上下文中调用的。组件用户不必担心多线程(这是我想要的主要目标) 组件用户可以在任何线程中创建我的非可视组件(UI线程只是简单应用程序的普通线程。更严重的应用程序可以在任意工作线程中创建组件)。组件触发事件,如“SessionConnected”或“DataAvailable” 问题:由于异步回调和其中引发的事件,事件处理程序在工作线程上下文中执行。

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

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

问题:由于异步回调和其中引发的事件,事件处理程序在工作线程上下文中执行。我想用一个中间层,这个力 要在创建事件的线程上下文中执行的事件处理程序 首先是组件

示例代码(从异常处理等中剥离)

//
///在连接结束时发生
/// 
///IAsyncResult从中读取信息
专用void EndConnect(IAsyncResult ar)
{
//通过事件传递连接状态
此.Socket.EndConnect(ar);
this.Stream=新的网络流(this.Socket);
//--这里的火灾事件--
//安装程序接收回调
这个.Receive();
}
/// 
///在数据接收完成时发生;当收到0字节时,我们可以假定连接已关闭,因此应该断开连接
/// 
///BeginRead使用的IAsyncResult
专用void EndReceive(IAsyncResult ar)
{
整数字节;
n字节=this.Stream.EndRead(ar);
如果(n字节>0)
{
//--此处的火灾接收数据事件--
//设置下一个接收回调
如果(此连接)
这个.Receive();
}
其他的
{
这个.Disconnect();
}
}
由于异步套接字的性质,所有使用我的组件的应用程序都充斥着“If(this.invokererequired){…”,我只想让用户能够使用我的组件,而不用担心,就像是一个插件

那么,我如何在不要求用户检查InvokeRequired的情况下引发事件(或者,换言之,我如何强制在与最初启动事件的线程相同的线程中引发事件)

我读过关于AsyncOperation、BackgroundWorkers、SynchronizingObject、AsyncCallbacks和其他很多东西,但这些都让我头晕目眩

我确实提出了这个,当然是笨拙的“解决方案”,但在某些情况下它似乎失败了(例如,当我的组件从WinForms项目通过静态类调用时)

//
///引发事件,确保为需要调用的控件调用BeginInvoke
/// 
/// 
/// 
/// http://www.eggheadcafe.com/articles/20060727.asp
受保护的void RaiseEvent(委托事件委托,对象[]args)
{
if(eventDelegate!=null)
{
尝试
{
控件ed=eventDelegate.Target作为控件;
如果((ed!=null)&(ed.invokererequired))
ed.Invoke(eventDelegate,args);
其他的
eventDelegate.DynamicInvoke(args);
}
捕获(例外情况除外)
{
WriteLine(例如GetType());
控制台写入线(例如消息);
//吞咽
}
}
}
任何帮助都将不胜感激。提前感谢

编辑:
据我所知,最好的办法是使用SyncrhonizationContext.Post,但我不知道如何将其应用于我的情况。

也许我不理解这个问题,但在我看来,您可以在异步状态下传递对自定义对象的引用

我把下面的例子放在一起加以说明

首先我们有一个回调对象,它有两个属性——一个用于分派操作的控件和一个用于调用的操作

public class Callback
{
    public Control Control { get; set; }
    public Action Method { get; set; }
}
然后我有一个WinForms项目,它调用另一个线程上的一些随机代码(使用BeginInvoke),然后在代码执行完成时显示一个messagebox

    private void Form1_Load(object sender, EventArgs e)
    {
        Action<bool> act = (bool myBool) =>
            {
                Thread.Sleep(5000);
            };

        act.BeginInvoke(true, new AsyncCallback((IAsyncResult result) =>
        {
            Callback c = result.AsyncState as Callback;
            c.Control.Invoke(c.Method);

        }), new Callback()
        {
            Control = this,
            Method = () => { ShowMessageBox(); }
        });            
    }

这就是您想要的吗?

如果您的组件必须始终由同一线程使用,您可以执行以下操作:

public delegate void CallbackInvoker(Delegate method, params object[] args);

public YourComponent(CallbackInvoker invoker)
{
    m_invoker = invoker;
}

protected void RaiseEvent(Delegate eventDelegate, object[] args)
{
    if (eventDelegate != null)
    {
        try
        {
            if (m_invoker != null)
                m_invoker(eventDelegate, args);
            else
                eventDelegate.DynamicInvoke(args);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType());
            Console.WriteLine(ex.Message);
            //Swallow
        }
    }
}
然后,当您从表单或其他控件实例化组件时,可以执行以下操作:

YourComponent c = new YourComponent(this.Invoke);

要在非UI工作线程上对事件进行排队,它必须具有某种工作排队机制,然后您可以提供一个具有CallbackInvoker签名的方法,以便在工作线程上对委托进行排队。

我似乎找到了解决方案:

    private SynchronizationContext _currentcontext

    /// Constructor of my component:
    MyComponent() {
        _currentcontext = WindowsFormsSynchronizationContext.Current;
       //...or...?
        _currentcontext = SynchronizationContext.Current;
    }

    /// <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)
        {
            if (_currentcontext != null)
                _currentcontext.Post(new System.Threading.SendOrPostCallback(
                    delegate(object a)
                    {
                        eventDelegate.DynamicInvoke(a as object[]);
                    }), args);
            else
                eventDelegate.DynamicInvoke(args);
        }
    }
private SynchronizationContext\u currentcontext
///我的组件的构造函数:
MyComponent(){
_currentcontext=WindowsFormsSynchronizationContext.Current;
//…还是。。。?
_currentcontext=SynchronizationContext.Current;
}
/// 
///引发事件,确保上下文正确
/// 
/// 
/// 
受保护的void RaiseEvent(委托事件委托,对象[]args)
{
if(eventDelegate!=null)
{
如果(_currentcontext!=null)
_currentcontext.Post(新的System.Threading.SendOrPostCallback(
委托(对象a)
{
DynamicInvoke(作为对象[])的事件代理;
}),args);
其他的
eventDelegate.DynamicInvoke(args);
}
}

我仍在测试,但它似乎运行良好。

好的;因此,我在阅读了更多内容后得出以下结论:

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);
        }
    }
}
公共类MyComponent{
专用异步操作\u异步操作;
///我的组件的构造函数:
MyComponent(){
_asyncOperation=AsyncOperationManager.CreateOperation(空);
}
///
YourComponent c = new YourComponent(this.Invoke);
    private SynchronizationContext _currentcontext

    /// Constructor of my component:
    MyComponent() {
        _currentcontext = WindowsFormsSynchronizationContext.Current;
       //...or...?
        _currentcontext = SynchronizationContext.Current;
    }

    /// <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)
        {
            if (_currentcontext != null)
                _currentcontext.Post(new System.Threading.SendOrPostCallback(
                    delegate(object a)
                    {
                        eventDelegate.DynamicInvoke(a as object[]);
                    }), args);
            else
                eventDelegate.DynamicInvoke(args);
        }
    }
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);
        }
    }
}