C# 向Windows窗体消息循环发送或发布消息
我有一个线程从命名管道读取消息。它是一个阻塞读取,这就是为什么它在自己的线程中。当该线程读取消息时,我希望它通知主线程中运行的Windows窗体消息循环消息已准备就绪。我该怎么做?在win32中,我会执行PostMessage,但该函数在.Net中似乎不存在(或者至少我找不到它)。C# 向Windows窗体消息循环发送或发布消息,c#,winforms,multithreading,messages,C#,Winforms,Multithreading,Messages,我有一个线程从命名管道读取消息。它是一个阻塞读取,这就是为什么它在自己的线程中。当该线程读取消息时,我希望它通知主线程中运行的Windows窗体消息循环消息已准备就绪。我该怎么做?在win32中,我会执行PostMessage,但该函数在.Net中似乎不存在(或者至少我找不到它)。PostMessage(同样SendMessage)是win32 API函数,因此与.Net没有直接关联。NET确实很好地支持使用P/Invoke调用与Win32 API进行互操作 由于您似乎对Win32 progra
PostMessage
(同样SendMessage
)是win32 API函数,因此与.Net没有直接关联。NET确实很好地支持使用P/Invoke调用与Win32 API进行互操作
由于您似乎对Win32 programming.NET还不熟悉,因此提供了有关该主题的详细介绍
详细说明如何使用C#/VB.NET中的许多API函数。专门用于PostMessage
标准声明如下:
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
但正如页面所示,明智的做法是包装此函数以正确处理Win32错误:
void PostMessageSafe(HandleRef hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
bool returnValue = PostMessage(hWnd, msg, wParam, lParam);
if(!returnValue)
{
// An error occured
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
您实际上是想将消息发布到消息循环中,还是只是想更新表单中的某些控件、显示消息框等。?如果是前者,请参考@Noldorin的回答。如果是后者,则需要使用Control.Invoke()方法将调用从“读取”线程封送到主UI线程。这是因为控件只能由创建它们的线程更新 这是.NET中相当标准的东西。请参阅以下MSDN文章以了解基本知识:
- (请参阅社区内容中的第一个示例)
一旦您了解了如何做到这一点,请参阅如何改进规范化技术。在WinForms中,您可以使用。例如:
public class SomethingReadyNotifier
{
private readonly Control synchronizer = new Control();
/// <summary>
/// Event raised when something is ready. The event is always raised in the
/// message loop of the thread where this object was created.
/// </summary>
public event EventHandler SomethingReady;
protected void OnSomethingReady()
{
SomethingReady?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Causes the SomethingReady event to be raised on the message loop of the
/// thread which created this object.
/// </summary>
/// <remarks>
/// Can safely be called from any thread. Always returns immediately without
/// waiting for the event to be handled.
/// </remarks>
public void NotifySomethingReady()
{
this.synchronizer.BeginInvoke(new Action(OnSomethingReady));
}
}
我不一定要使用PostMessage。难道没有简单的.Net方法来做我想做的事情吗?迈克是对的。您使用的是基于Win32 API的Windows消息循环,因此需要P/Invoke。
public class SomethingReadyNotifier
{
private readonly SynchronizationContext synchronizationContext;
/// <summary>
/// Create a new <see cref="SomethingReadyNotifier"/> instance.
/// </summary>
/// <param name="synchronizationContext">
/// The synchronization context that will be used to raise
/// <see cref="SomethingReady"/> events.
/// </param>
public SomethingReadyNotifier(SynchronizationContext synchronizationContext)
{
this.synchronizationContext = synchronizationContext;
}
/// <summary>
/// Event raised when something is ready. The event is always raised
/// by posting on the synchronization context provided to the constructor.
/// </summary>
public event EventHandler SomethingReady;
private void OnSomethingReady()
{
SomethingReady?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Causes the SomethingReady event to be raised.
/// </summary>
/// <remarks>
/// Can safely be called from any thread. Always returns immediately without
/// waiting for the event to be handled.
/// </remarks>
public void NotifySomethingReady()
{
this.synchronizationContext.Post(
state => OnSomethingReady(),
state: null);
}
}