我写了一个简单的客户端,在dotnet中使用TcpClient进行通信。为了等待来自服务器的数据消息,我使用Read()
线程在socket上使用阻塞Read()
调用。当我收到的东西,我必须生成各种事件。这些事件发生在工作线程中,因此您无法直接从其更新UI。 Invoke()
可以使用,但对于最终开发人员来说很困难,因为我的SDK可能会被完全不使用UI或使用Presentation Framework的用户使用。演示框架有不同的处理方式。 Invoke()
在我们的测试应用上,Microstation Addin目前需要花费大量时间。 Microstation是单线程应用程序,并且在其线程上调用调用并不好,因为它总是忙于绘图,而其他消息需要花费太长时间来处理。
我希望我的事件在与UI相同的线程中生成,因此用户不必通过Dispatcher
或Invoke
。
现在我想知道当数据到达时如何通过套接字通知我?是否有内置回调。我喜欢winsock样式接收事件而不使用单独的读取线程。我也不想使用窗口计时器来轮询数据。
我在IOControlCode.AsyncIO
函数中找到了IOControl()
标记,这有助于说明
启用数据时间通知 等待收到。这个值是 等于Winsock 2
FIOASYNC
恒定。
我找不到任何关于如何使用它来获取通知的示例。如果我在MFC / Winsock中是正确的,我们必须创建一个size(0,0)
窗口,该窗口仅用于监听数据接收事件或其他套接字事件。但我不知道如何在dotnet应用程序中这样做。
答案 0 :(得分:1)
好的,我把它拿起来跑了。我真正想要的是如何将事件无缝地发布到UI线程,在该线程中创建了我的连接。在完成框架代码之后,我想出了以下概念证明。 SynchronizationContext
可用于将我的组件绑定到创建它的UI线程。然后我可以直接将事件发布到该UI线程,而不使用Invoke
。
在下面的示例中,我创建了一个ThreadUISafeTimer
,它使用了一个单独的线程,就像我的socket客户端一样,用于读取和引发事件。在这种情况下,context
用于发布事件(如果不为null),否则使用工作线程引发事件。
[DefaultEvent("Tick")]
public class ThreadUISafeTimer : Component
{
private const int True = 1;
private const int False = 0;
private int enabled = False;
private SynchronizationContext context;
public event EventHandler Tick = delegate { };
[DefaultValue(false)]
public ushort Interval { get; set; }
public ThreadUISafeTimer() {
Interval = 100;
this.Events.AddHandler("Tick", Tick);
//If this class is created by a UI thread it will always post the Tick event to it.
//otherwise it would be null and Tick would occur in a seperate thread.
context = SynchronizationContext.Current;
}
protected override bool CanRaiseEvents {
get {
return true;
}
}
[DefaultValue(false)]
public bool Enabled {
get {
return enabled == True;
}
set {
int newval = value ? True : False;
if (enabled != newval) {
if (newval == False)
Thread.VolatileWrite(ref enabled, False);
else {
enabled = True;
ThreadPool.QueueUserWorkItem(
new WaitCallback(delegate(object o) {
try {
do {
try {
Thread.Sleep(Interval);
if (Thread.VolatileRead(ref enabled) == True) {
var callback = new SendOrPostCallback(delegate(object arg) {
try {
Tick(this, EventArgs.Empty);
}
catch (Exception exp) {
Application.OnThreadException(exp);
return;
}
});
//If context is null raise Tick event from current thread
if (context == null)
callback(null);
else
//otherwise post it to the UI thread that owns this timer.
context.Post(callback, null);
}
}
catch (ThreadInterruptedException) {
}
} while (Thread.VolatileRead(ref enabled) == True);
}
catch (ThreadAbortException) {
}
}), null);
}
}
}
}
答案 1 :(得分:0)
看看这个大致相同的问题,并使用Event Broker模式解决。
Sending instructions to a thread which is waiting for TCP?
基本上你会有一个对象包含你所有线程都订阅的事件。它还将有一个可以调用的方法来调用该事件。这可能听起来很复杂,但相当简单。