【发布时间】:2015-01-15 07:28:55
【问题描述】:
在常规 WinAPI 中,您可以使用 PostMessage 将消息发送到应用程序内的窗口,该窗口不会等待消息被处理,它会立即返回。
现在在我的窗口中,我收到了在同一个 UI 线程中调用的这条消息,我可以在其中操作其他一些 UI 控件。
如何在 .NET WinForms 中模拟这种行为?
我知道我可以使用 Delegate.BeginInvoke 来异步调用我的方法,但它不会在同一个 UI 线程中执行,并且对 UI 控件的任何访问都会引发异常。我知道我可以使用 Control.Invoke 来更改该方法中的 UI,但这对于编写代码来说太多了,我不想为此担心,并以与 WinAPI 中相同的方式工作。
我有这样的代码
public delegate void DoDelegate();
private DoDelegate d;
public Form1()
{
InitializeComponent();
d = new DoDelegate(Do);
}
private void button1_Click(object sender, EventArgs e)
{
d.BeginInvoke(ar =>
{
AsyncResult result = (AsyncResult)ar;
DoDelegate dd = (DoDelegate)result.AsyncDelegate;
dd.EndInvoke(ar);
}, null);
}
public void Do()
{
Action a = () =>
{
for (int i = 0; i < 10; i++)
{
label1.Text = "Item " + i;
Thread.Sleep(1000);
}
};
if (InvokeRequired)
Invoke(a);
else a();
}
即使在单独的线程中调用也会阻塞主线程。我知道为什么,因为我在整个方法上使用 Control.Invoke,并且我应该只在设置 .Text 属性时使用它,但同样,这太多了,很容易忘记使用 Invoke 然后所有崩溃。
所以,基本上,我如何调用异步方法,它不会在没有调用机制的情况下访问 UI 产生任何问题,就像我使用 PostMessage 所做的一样?
想法?
【问题讨论】:
-
这完全没有意义。
Thread.Sleep(1000)阻塞它执行的任何线程。如果您不想阻止,请不要致电Sleep。如果您想避免阻塞工作线程,请使用BeginInvoke。 -
为此,我需要引用一个控件,而我不需要。但我发现我可以使用这样的代码 SynchronizationContext.Current.Post(state => Do(), null);结果按预期工作。我知道它在后台使用 BeginInvoke,但至少我不必担心对有效控件的引用。
-
PostMessage需要窗口句柄