Отправьте или добавьте сообщение к циклу сообщения Windows Forms

Что-то, что работает на высокий процент встроенных классов, является тестом для Сопоставимого instanceof. Для классов, которые не неизменны как Дата, их часто рассматривают как неизменных в большинстве случаев.

16
задан dan-gph 5 March 2018 в 23:14
поделиться

3 ответа

В WinForms этого можно добиться с помощью Control.BeginInvoke . Пример:

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

Более чистый вариант вышеперечисленного, который не зависит от WinForms, будет использовать SynchronizationContext . Вызовите SynchronizationContext.Current в основном потоке, а затем передайте эту ссылку конструктору класса, показанного ниже.

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);
        }
    }
16
ответ дан 30 November 2019 в 16:30
поделиться

PostMessage (и аналогично SendMessage ) являются функциями Win32 API и, следовательно, не связаны напрямую с .NET. Однако .NET имеет хорошую поддержку взаимодействия с Win32 API с использованием вызовов P / Invoke.

Поскольку кажется, что вы новичок в программировании .NET для Win32, эта статья журнала MSDN Magazine дает хорошее введение по теме.

Отличный веб-сайт pinvoke.net подробно описывает, как использовать многие из этих функций API из C # / VB.NET. См. Эту страницу для 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());
    }
}        
18
ответ дан 30 November 2019 в 16:30
поделиться

Вы действительно хотите опубликовать сообщение в цикл сообщений или вы просто хотите обновить какой-либо элемент управления в своей форме, отобразить окно сообщения и т. д.? Если это первое, обратитесь к ответу @Noldorin. Если последнее, то вам нужно использовать метод Control.Invoke () для маршалинга вызова из вашего «читающего» потока в основной поток пользовательского интерфейса. Это потому, что элементы управления могут быть обновлены только тем потоком, в котором они были созданы.

Это довольно стандартная вещь в .NET. Обратитесь к этим статьям MSDN, чтобы получить основы:

Как только вы поймете, как это сделать,

5
ответ дан 30 November 2019 в 16:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: