gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 20:35:34 25 4
gpt4 key购买 nike

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

组件用户可以在任何线程中创建我的非可视组件(UI 线程只是简单应用程序的公共(public)线程。更严肃的应用程序可以在任意工作线程中创建组件)。组件触发事件,例如“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();
}
}

由于异步套接字的性质,所有使用我的组件的应用程序都充斥着“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
}
}
}

如有任何帮助,我们将不胜感激。提前致谢!

编辑:根据this thread我最好的选择是使用 SyncrhonizationContext.Post,但我不知道如何将它应用到我的情况。

最佳答案

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

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

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

关于c# - 从 UI 线程中的异步组件触发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2022063/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com