Como lidar com mensagens WndProc no WPF?

Encontrando o WPF uma curva de aprendizagem íngreme.

No bom e velho Windows Forms, eu apenas substitui o WndProc , e começo a manipular as mensagens quando elas chegam.

Alguém pode me mostrar um exemplo de como conseguir a mesma coisa no WPF?

Na verdade, tanto quanto eu entendo uma coisa dessas é realmente possível no WPF usando HwndSource e HwndSourceHook . Veja este tópico no MSDN como um exemplo. (Código relevante incluído abaixo)

 // '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; } 

Agora, não sei bem por que você iria querer lidar com mensagens do Windows Messaging em um aplicativo WPF (a menos que seja a forma mais óbvia de interoperabilidade para trabalhar com outro aplicativo WinForms). A ideologia do design e a natureza da API são muito diferentes no WPF do WinForms, então eu sugiro que você se familiarize mais com o WPF para ver exatamente por que não há equivalente do WndProc.

Você pode fazer isso através do namespace System.Windows.Interop que contém uma class chamada HwndSource .

Exemplo de uso deste

 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; } } } 

Completamente tirado do excelente post do blog: Usando um WndProc personalizado em aplicativos WPF por Steve Rands (note que o link não é mais válido)

Este site está inativo agora, mas você pode vê-lo a partir do mecanismo do Wayback: http://web.archive.org/web/20091019124817/http://www.steverands.com/2009/03/19/custom-wndproc-wpf -apps /

 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; } 

Há maneiras de manipular mensagens com um WndProc no WPF (por exemplo, usando um HwndSource, etc.), mas geralmente essas técnicas são reservadas para interoperabilidade com mensagens que não podem ser manipuladas diretamente por meio do WPF. A maioria dos controles WPF não são nem mesmo janelas no sentido Win32 (e por extensão Windows.Forms), então eles não terão WndProcs.

Você pode append à class ‘SystemEvents’ da class Win32 interna:

 using Microsoft.Win32; 

em uma class de janela do 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(); } } 

Se você não se importar em fazer referência ao WinForms, poderá usar uma solução mais orientada para o MVVM que não atenda o serviço com a exibição. Você precisa criar e inicializar um System.Windows.Forms.NativeWindow, que é uma janela leve que pode receber mensagens.

 public abstract class WinApiServiceBase : IDisposable { ///  /// Sponge window absorbs messages and lets other services use them ///  private sealed class SpongeWindow : NativeWindow { public event EventHandler 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); } ///  /// Override to process windows messages ///  protected virtual void WndProc(Message message) { } public virtual void Dispose() { Sponge.WndProced -= LocalWndProced; } } 

Use o SpongeHandle para registrar as mensagens de seu interesse e, em seguida, substitua o WndProc para processá-las:

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

A única desvantagem é que você tem que include a referência System.Windows.Forms, mas caso contrário, esta é uma solução muito encapsulada.

Mais sobre isso pode ser lido aqui

O WPF não opera no tipo WinForms wndprocs

Você pode hospedar um HWndHost em um elemento WPF apropriado e depois replace o wndproc do Hwndhost, mas o AFAIK é o mais próximo possível.

http://msdn.microsoft.com/pt-br/library/ms742522.aspx

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

A resposta curta é que você não pode. WndProc funciona passando mensagens para um HWND em um nível Win32. As janelas do WPF não têm HWND e, portanto, não podem participar de mensagens WndProc. O loop de mensagem base do WPF fica sobre o WndProc, mas abstrai-os da lógica principal do WPF.

Você pode usar um HWndHost e obter um WndProc para ele. No entanto, isso quase certamente não é o que você quer fazer. Para a maioria das finalidades, o WPF não opera em HWND e WndProc. Sua solução quase certamente depende de fazer uma alteração no WPF não no WndProc.