如何处理WPF中的WndProc消息?

寻找WPF陡峭的学习曲线。

在好的Windows窗体中,我只是重写WndProc ,并开始处理消息。

有人可以告诉我一个如何在WPF中实现相同的事情的例子吗?

其实,就我所知,WPF中使用HwndSourceHwndSourceHook确实有这样的可能。 以MSDN上的这个线程为例。 (相关代码如下)

 // 'this' is a Window HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); source.AddHook(new HwndSourceHook(WndProc)); private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { // do stuff return IntPtr.Zero; } 

现在,我不太清楚为什么要在WPF应用程序中处理Windows消息消息(除非它是与另一个WinForms应用程序一起工作的最显而易见的互操作forms)。 从WinForms的devise思想和API的本质是非常不同的WPF,所以我build议你只是熟悉WPF更多,看看为什么没有相当于WndProc。

您可以通过包含名为HwndSource的类的System.Windows.Interop命名空间来执行此操作。

使用这个例子

 using System; using System.Windows; using System.Windows.Interop; namespace WpfApplication1 { public partial class Window1 : Window { public Window1() { InitializeComponent(); } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource source = PresentationSource.FromVisual(this) as HwndSource; source.AddHook(WndProc); } private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { // Handle messages... return IntPtr.Zero; } } } 

完全取自优秀的博客文章: 在Steve Rands的WPF应用程序中使用自定义的WndProc (注意,链接不再有效)

现在这个网站已经closures了,但是你可以从Wayback引擎中看到: http ://web.archive.org/web/20091019124817/http: //www.steverands.com/2009/03/19/custom-wndproc-wpf -应用/

 HwndSource src = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); src.AddHook(new HwndSourceHook(WndProc)); ....... public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if(msg == THEMESSAGEIMLOOKINGFOR) { //Do something here } return IntPtr.Zero; } 

你可以在这里find附加到WndProc的另一个解释。

有一些方法可以用WPF中的WndProc处理消息(例如,使用HwndSource等),但是通常这些技术是为了与不能直接通过WPF处理的消息进行互操作而保留的。 大多数WPF控件甚至不是Win32(和扩展Windows.Forms)的意义上的窗口,所以他们不会有WndProcs。

您可以附加到内置的Win32类的“SystemEvents”类:

 using Microsoft.Win32; 

在WPF窗口类中:

 SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; SystemEvents.SessionEnding += SystemEvents_SessionEnding; SystemEvents.SessionEnded += SystemEvents_SessionEnded; private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { await vm.PowerModeChanged(e.Mode); } private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { await vm.PowerModeChanged(e.Mode); } private async void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) { await vm.SessionSwitch(e.Reason); } private async void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) { if (e.Reason == SessionEndReasons.Logoff) { await vm.UserLogoff(); } } private async void SystemEvents_SessionEnded(object sender, SessionEndedEventArgs e) { if (e.Reason == SessionEndReasons.Logoff) { await vm.UserLogoff(); } } 

如果您不介意引用WinForms,则可以使用更多的面向MVVM的解决scheme,而不将服务与视图耦合。 您需要创build并初始化一个System.Windows.Forms.NativeWindow,它是一个可以接收消息的轻量级窗口。

 public abstract class WinApiServiceBase : IDisposable { /// <summary> /// Sponge window absorbs messages and lets other services use them /// </summary> private sealed class SpongeWindow : NativeWindow { public event EventHandler<Message> WndProced; public SpongeWindow() { CreateHandle(new CreateParams()); } protected override void WndProc(ref Message m) { WndProced?.Invoke(this, m); base.WndProc(ref m); } } private static readonly SpongeWindow Sponge; protected static readonly IntPtr SpongeHandle; static WinApiServiceBase() { Sponge = new SpongeWindow(); SpongeHandle = Sponge.Handle; } protected WinApiServiceBase() { Sponge.WndProced += LocalWndProced; } private void LocalWndProced(object sender, Message message) { WndProc(message); } /// <summary> /// Override to process windows messages /// </summary> protected virtual void WndProc(Message message) { } public virtual void Dispose() { Sponge.WndProced -= LocalWndProced; } } 

使用SpongeHandle注册你感兴趣的消息,然后覆盖WndProc来处理它们:

 public class WindowsMessageListenerService : WinApiServiceBase { protected override void WndProc(Message message) { Debug.WriteLine(message.msg); } } 

唯一的缺点是你必须包含System.Windows.Forms引用,否则这是一个非常封装的解决scheme。

更多关于这个可以在这里阅读

WPF不能在WinFormstypes的wndprocs上运行

您可以在适当的WPF元素中托pipe一个HWndHost,然后覆盖Hwndhost的wndproc,但AFAIK就像您将要获得的一样。

http://msdn.microsoft.com/en-us/library/ms742522.aspx

http://blogs.msdn.com/nickkramer/archive/2006/03/18/554235.aspx

简短的答案是你不能。 WndProc通过将消息传递给Win32级别的HWND来工作。 WPF窗口没有HWND,因此不能参与WndProc消息。 基本的WPF消息循环确实位于WndProc之上,但它将它们从核心WPF逻辑中抽象出来。

你可以使用HWndHost并获得一个WndProc。 但是,这几乎肯定不是你想要做的。 对于大多数的目的,WPF不能在HWND和WndProc上运行。 你的解决scheme几乎肯定依赖于WPF中的更改,而不是在WndProc中。