Что-то, что работает на высокий процент встроенных классов, является тестом для Сопоставимого instanceof. Для классов, которые не неизменны как Дата, их часто рассматривают как неизменных в большинстве случаев.
В 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);
}
}
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());
}
}
Вы действительно хотите опубликовать сообщение в цикл сообщений или вы просто хотите обновить какой-либо элемент управления в своей форме, отобразить окно сообщения и т. д.? Если это первое, обратитесь к ответу @Noldorin. Если последнее, то вам нужно использовать метод Control.Invoke () для маршалинга вызова из вашего «читающего» потока в основной поток пользовательского интерфейса. Это потому, что элементы управления могут быть обновлены только тем потоком, в котором они были созданы.
Это довольно стандартная вещь в .NET. Обратитесь к этим статьям MSDN, чтобы получить основы:
Как только вы поймете, как это сделать,