Comment gérer les messages WndProc dans WPF?

Trouver WPF une courbe d’apprentissage raide.

Dans le bon vieux Windows Forms, je remplacerais simplement WndProc et commencerais à gérer les messages dès leur arrivée.

Quelqu’un peut-il me montrer un exemple de la façon d’obtenir la même chose dans WPF?

En fait, pour autant que je HwndSource , une telle chose est effectivement possible dans WPF en utilisant HwndSource et HwndSourceHook . Voir ce fil sur MSDN comme exemple. (Code pertinent inclus ci-dessous)

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

Maintenant, je ne sais pas trop pourquoi vous souhaitez gérer les messages Windows Messaging dans une application WPF (à moins que ce ne soit la forme d’interopérabilité la plus évidente pour travailler avec une autre application WinForms). L’idéologie du design et la nature de l’API sont très différentes dans WinForms de WPF. Je vous suggère donc de vous familiariser davantage avec WPF pour savoir exactement pourquoi WndProc n’est pas équivalent.

Vous pouvez le faire via l’espace de noms System.Windows.Interop qui contient une classe nommée HwndSource .

Exemple d’utilisation

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

Complètement tiré de l’excellent article de blog: Utilisation d’un WndProc personnalisé dans les applications WPF par Steve Rands (note, le lien n’est plus valide)

Ce site est en panne maintenant, mais vous pouvez le voir sur le moteur Wayback: http://web.archive.org/web/20091019124817/http://www.steverands.com/2009/03/19/custom-wndproc-wpf -applications/

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

Il existe des moyens de gérer les messages avec un WndProc dans WPF (par exemple, en utilisant un HwndSource, etc.), mais ces techniques sont généralement réservées à l’interopérabilité avec des messages qui ne peuvent pas être directement traités via WPF. La plupart des contrôles WPF ne sont même pas des fenêtres dans le sens Win32 (et par extension Windows.Forms), ils n’auront donc pas WndProcs.

Vous pouvez attacher à la classe ‘SystemEvents’ de la classe Win32 intégrée:

 using Microsoft.Win32; 

dans une classe de fenêtre 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(); } } 

Si cela ne vous dérange pas de faire référence à WinForms, vous pouvez utiliser une solution plus orientée MVVM qui n’associe pas le service à la vue. Vous devez créer et initialiser System.Windows.Forms.NativeWindow, une fenêtre légère capable de recevoir des messages.

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

Utilisez SpongeHandle pour vous inscrire aux messages qui vous intéressent, puis remplacez WndProc pour les traiter:

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

Le seul inconvénient est que vous devez inclure la référence System.Windows.Forms, mais sinon c’est une solution très encapsulée.

Plus sur ceci peut être lu ici

WPF ne fonctionne pas sur le type WinForms wndprocs

Vous pouvez héberger un HWndHost dans un élément WPF approprié, puis remplacer le wndproc de Hwndhost, mais AFAIK est le plus proche possible.

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

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

La réponse courte est que vous ne pouvez pas. WndProc fonctionne en transmettant des messages à un HWND au niveau Win32. Les fenêtres WPF n’ont pas de HWND et ne peuvent donc pas participer aux messages WndProc. La boucle de messages WPF de base repose sur WndProc, mais elle les éloigne de la logique WPF principale.

Vous pouvez utiliser un HWndHost et obtenir un WndProc pour cela. Cependant, ce n’est certainement pas ce que vous voulez faire. Dans la majorité des cas, WPF ne fonctionne pas sur HWND et WndProc. Votre solution repose presque certainement sur la modification de WPF et non sur WndProc.