Send or post a message to a Windows Forms message loop

c#, message, multithreading, winforms

Solution

In WinForms you can achieve this with Control.BeginInvoke. An example:

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

A cleaner variant of the above which doesn't depend on WinForms would be to use `SynchronizationContext`. Call SynchronizationContext.Current on your main thread, and then pass that reference to the constructor of the class shown below.

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

Problem

I have a thread that reads messages from a named pipe. It is a blocking read, which is why it's in its own thread. When this thread reads a message, I want it to notify the Windows Forms message loop running in the main thread that a message is ready. How can I do that? In win32 I would do a PostMessage, but that function does not seem to exist in .Net (or at least I could not find it).

Original source