Question

Trouver WPF est une courbe d'apprentissage abrupte.

Dans le bon vieux Windows Forms, je substituerais simplement WndProc et commencerais à gérer les messages au fur et à mesure de leur arrivée.

Quelqu'un peut-il me montrer un exemple de la façon de réaliser la même chose dans WPF?

Était-ce utile?

La solution

En fait, pour autant que je sache, une telle chose est effectivement possible dans WPF avec HwndSource et HwndSourceHook . Voir ce fil de discussion sur MSDN à titre d'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;
}

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

Autres conseils

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

Exemple d'utilisation de cette

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 de Steve Rands

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

Si le fait de référencer WinForms ne vous dérange pas, vous pouvez utiliser une solution davantage axée sur MVVM qui ne couple pas le service à la vue. Vous devez créer et initialiser une System.Windows.Forms.NativeWindow qui est une fenêtre légère pouvant recevoir des messages.

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

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, il s'agit d'une solution très encapsulée.

Pour en savoir plus, consultez ici

.

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 pour l’interopérabilité avec des messages qui ne peuvent pas être gérés directement par WPF. La plupart des contrôles WPF ne sont même pas des fenêtres au sens Win32 (et par extension Windows.Forms), ils n'auront donc pas WndProcs.

Vous pouvez vous connecter à la classe 'SystemEvents' de la classe intégrée Win32:

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

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 du Hwndhost, mais autant que je sache, vous serez aussi proche que 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 message WPF de base repose sur WndProc mais 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 plupart des cas, WPF ne fonctionne pas sur HWND et WndProc. Votre solution repose presque certainement sur une modification de WPF et non de WndProc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top