dan*_*gph 16 c# multithreading messages winforms
我有一个线程从命名管道读取消息.这是一个阻塞读取,这就是为什么它在自己的线程中.当此线程读取消息时,我希望它通知在主线程中运行的Windows窗体消息循环消息已准备好.我怎样才能做到这一点?在win32中我会做一个PostMessage,但该功能似乎不存在于.Net(或者至少我找不到它).
Nol*_*rin 18
PostMessage
(同样SendMessage
)是Win32 API函数,因此不直接与.NET相关联.但是,.NET确实支持使用P/Invoke调用与Win32 API进行交互.
由于您似乎不熟悉Win32编程.NET,因此本MSDN杂志文章提供了有关该主题的可靠介绍.
优秀的pinvoke.net网站详细介绍了如何使用C#/ VB.NET中的许多API函数.看到这个页面的PostMessage
具体.
标准声明如下:
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
但正如页面所示,最好包装此函数以正确处理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());
}
}
Run Code Online (Sandbox Code Playgroud)
Wim*_*nen 16
在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));
}
}
Run Code Online (Sandbox Code Playgroud)
将使用不依赖于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);
}
}
Run Code Online (Sandbox Code Playgroud)
您是否真的要在消息循环中发布消息,还是只是想更新表单中的某些控件,显示消息框等?如果是前者,请参阅@Noldorin的回复。如果是后者,则需要使用Control.Invoke()方法将从“读取”线程到主UI线程的调用编组。这是因为只能通过创建控件的线程来更新控件。
这是.NET中非常标准的事情。请参阅以下MSDN文章以获取基础知识:
了解了如何执行此操作后,请参考Peter Duniho的博客,以了解如何改进规范技术。
归档时间: |
|
查看次数: |
23641 次 |
最近记录: |