C# 向Windows窗体消息循环发送或发布消息

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

我有一个线程从命名管道读取消息。它是一个阻塞读取,这就是为什么它在自己的线程中。当该线程读取消息时,我希望它通知主线程中运行的Windows窗体消息循环消息已准备就绪。我该怎么做?在win32中,我会执行PostMessage,但该函数在.Net中似乎不存在(或者至少我找不到它)。

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