Domanda

Trovare WPF una curva di apprendimento ripida.

In buona parte di Windows Form, vorrei semplicemente ignorare WndProc e iniziare a gestire i messaggi non appena venivano.

Qualcuno può mostrarmi un esempio di come ottenere la stessa cosa in WPF?

È stato utile?

Soluzione

In realtà, per quanto ho capito una cosa del genere è davvero possibile in WPF usando HwndSource e HwndSourceHook . Vedi questa discussione su MSDN come esempio. (Codice pertinente incluso di seguito)

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

Ora, non sono del tutto sicuro del motivo per cui vorresti gestire i messaggi di Windows Messaging in un'applicazione WPF (a meno che non sia la forma più ovvia di interoperabilità per lavorare con un'altra app WinForms). L'ideologia del design e la natura dell'API sono molto diverse in WPF da WinForms, quindi suggerirei di familiarizzare con WPF per vedere esattamente perché non esiste un equivalente di WndProc.

Altri suggerimenti

Puoi farlo tramite lo spazio dei nomi System.Windows.Interop che contiene una classe chiamata HwndSource .

Esempio di utilizzo di questo

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 tratto dall'eccellente post sul blog: Utilizzo di un WndProc personalizzato nelle app WPF di 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;
}

Se non ti dispiace fare riferimento a WinForms, puoi utilizzare una soluzione più orientata a MVVM che non abbina il servizio alla vista. Devi creare e inizializzare una System.Windows.Forms.NativeWindow che è una finestra leggera in grado di ricevere messaggi.

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

Usa SpongeHandle per registrarti per i messaggi che ti interessano e quindi sovrascrivi WndProc per elaborarli:

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

L'unico aspetto negativo è che devi includere il riferimento System.Windows.Forms, ma per il resto questa è una soluzione molto incapsulata.

Altre informazioni al riguardo possono essere lette qui

Esistono modi per gestire i messaggi con un WndProc in WPF (ad es. usando un HwndSource, ecc.), ma generalmente quelle tecniche sono riservate all'interoperabilità con messaggi che non possono essere gestiti direttamente tramite WPF. La maggior parte dei controlli WPF non sono nemmeno windows nel senso di Win32 (e per estensione Windows.Forms), quindi non avranno WndProcs.

Puoi collegarti alla classe 'SystemEvents' della classe Win32 integrata:

using Microsoft.Win32;

in una classe di finestra 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 non funziona su wndprocs di tipo WinForms

Puoi ospitare un HWndHost in un elemento WPF appropriato, quindi sovrascrivere il wndproc di Hwndhost, ma AFAIK è il più vicino possibile.

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

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

La risposta breve è che non puoi. WndProc funziona passando i messaggi a un HWND a livello Win32. Le finestre WPF non hanno HWND e quindi non possono partecipare ai messaggi WndProc. Il ciclo di messaggi WPF di base si trova in cima a WndProc ma li allontana dalla logica WPF di base.

Puoi usare un HWndHost e ottenere un WndProc per questo. Tuttavia, questo non è quasi certamente quello che vuoi fare. Per la maggior parte degli scopi, WPF non funziona su HWND e WndProc. La tua soluzione si basa quasi sicuramente su un cambiamento in WPF e non in WndProc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top