【问题标题】:Equivalent of Windows API PostMessage to self for a WPF/XAML app?等效于 WPF/XAML 应用程序的 Windows API PostMessage?
【发布时间】:2015-10-13 08:23:42
【问题描述】:

在 Windows 应用程序开发的“旧时代”,使用 PostMessage Windows API 函数将消息发布到您自己的应用程序是一种将特定任务的处理移出当前堆栈上下文的好方法,同时保留在主线程,从而避免尝试在另一个线程上执行主线程任务的细微差别(这当然会导致使用 Invoke 样式方法将处理移回主线程等)

你所要做的就是:

  • 使用大于 WM_USER 的数值创建自定义窗口消息
  • 使用 PostMessage 向您自己广播该消息
  • 向主对话窗口添加一个处理程序,以处理您的自定义 WM_* 消息的消息并对其执行操作

这使您可以将处理移出棘手的执行上下文,例如深入嵌套的调用堆栈中,可能使用持有资源锁的方法等,而是将处理延迟到“更干净”的执行上下文。

例如,我真的不喜欢在属性 setter/getter 中做很多事情,尤其是对于依赖属性,除了保存或恢复值。那和事件处理程序是执行上下文的两个主要示例,我想延迟与特定事件关联的任务并将其传递回主线程以在主线程执行的顶级执行上下文。

我想对我的 WPF/XAML 应用程序做同样的事情,但我只想使用托管代码,所以我不想使用 Windows API 调用,如果可能的话,所以我尽量避免做类似的事情显示在以下两个 SO 帖子中:

How to create C# Event to handle MFC Windows message from PostMessage()

What's the equivalent of PostMessage to self, for Windows Forms?

是否有与实现相同功能的 WPF/XAML 托管代码兼容的 C# 机制、习语等?。是否有 WPF/XAML 托管代码技术可以像 PostMessage 那样使用应用程序的输入队列?

注意,虽然我不是专家,但我已经多次使用 C# 的 Task.Run()、TaskFactory.StartNew()、Control.BeginInvoke()、async/await 等工具。正如我所说,我正在寻找一些希望不需要创建新线程或任何其他不寻常的编码体操的东西。

【问题讨论】:

  • “使用 PostMessage....是移动特定任务处理的好方法”——我对“伟大”这个词的使用提出异议在那里。请注意,PostMessage() 具有比这更广泛的功能;这种情况下的影响与任何事情一样都是副作用。但是,是的,这是人们实现这一目标的一种方式。 Winforms 等价物是Control.BeginInvoke()(您已经使用过),WPF 等价物是Dispatcher.BeginInvoke()。不过,Stack Overflow 确实不是这种 API 研究的最佳场所。首先要从 API 本身的文档开始。
  • +1。 PostMessage 之所以起作用,是因为您可以在等待某些东西时运行单独的消息泵,从而产生异步行为的错觉。问题当然是,一旦你有两件事在等待,那么你就有潜在的死锁情况。 Async/wait 是 C# 机制,旨在通过确保异步代码在稍后恢复之前立即返回来替代这一点并防止死锁。

标签: c# wpf xaml postmessage delayed-execution


【解决方案1】:

好吧,我建议一开始就不要陷入这种情况。

也就是说,您可以async voidTask.Yield一起使用:

async void DoSomethingAsync()
{
  await Task.Yield();
  // Code here will run directly off the message loop.
}

Task.Yield 将导致方法立即返回,将方法的其余部分排队到消息循环中。 async void 会导致异常直接抛出到消息循环中。

嗯,你做到了。我刚刚发布了一个带有Task.Yield async void 的答案。 Blech,我现在要洗手了……

【讨论】:

  • 如果从工作线程(不是主线程)调用 DoSomethingAsync(),后 Yield() 语句代码是否仍会在主线程上运行? “async void”一直是我身边的刺。我在您的网站上阅读了很多内容,并且确实理解为什么应该避免它,尤其是出于异常处理的原因。但是在某些情况下,我发现自己在做真正痛苦的编码体操,试图避免它,并且总是放弃并无论如何都要去做。 MS 允许它用于事件处理程序这一事实向我表明,尽管要避免它,但它有明确的用例。
  • @RobertOschler: 不。这只是跳转到当前上下文顶层的一种方式,所以如果在线程池线程上运行,await 之后的代码将在不同的线程上执行池线程。需要明确的是,我永远不会在我的应用程序中允许这样的代码;总有更好的方法,可能是重新设计的一部分。
猜你喜欢
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 2010-11-27
相关资源
最近更新 更多