Pregunta

Encontrar WPF una curva de aprendizaje empinada.

En todos los formularios Windows Forms, anularía WndProc y comenzaría a manejar los mensajes a medida que llegaban.

¿Puede alguien mostrarme un ejemplo de cómo lograr lo mismo en WPF?

¿Fue útil?

Solución

En realidad, hasta donde entiendo, tal cosa es realmente posible en WPF usando HwndSource y HwndSourceHook . Vea este hilo en MSDN como ejemplo. (Código relevante incluido a continuación)

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

Ahora, no estoy muy seguro de por qué querría manejar los mensajes de Windows Messaging en una aplicación WPF (a menos que sea la forma más obvia de interoperabilidad para trabajar con otra aplicación WinForms). La ideología de diseño y la naturaleza de la API es muy diferente en WPF de WinForms, por lo que te sugiero que te familiarices más con WPF para ver exactamente por qué no hay equivalente de WndProc.

Otros consejos

Puede hacerlo a través del espacio de nombres System.Windows.Interop que contiene una clase llamada HwndSource .

Ejemplo de uso de este

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 tomado de la excelente publicación del blog: Uso de un WndProc personalizado en las aplicaciones 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 no le importa hacer referencia a WinForms, puede usar una solución más orientada a MVVM que no combine el servicio con la vista. Debe crear e inicializar un System.Windows.Forms.NativeWindow que es una ventana liviana que puede recibir mensajes.

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

Use SpongeHandle para registrarse en los mensajes que le interesen y luego invalide WndProc para procesarlos:

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

El único inconveniente es que debes incluir la referencia de System.Windows.Forms, pero de lo contrario, esta es una solución muy encapsulada.

Se puede leer más sobre esto aquí

Hay formas de manejar los mensajes con un WndProc en WPF (por ejemplo, usando un HwndSource, etc.), pero generalmente esas técnicas están reservadas para interoperar con mensajes que no se pueden manejar directamente a través de WPF. La mayoría de los controles de WPF ni siquiera son ventanas en el sentido de Win32 (y por extensión Windows.Forms), por lo que no tendrán WndProcs.

Puede adjuntar a la clase 'SystemEvents' de la clase incorporada de Win32:

using Microsoft.Win32;

en una clase de ventana 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 no funciona en WinForms tipo wndprocs

Puedes alojar un HWndHost en un elemento WPF apropiado y luego anular el wndproc de Hwndhost, pero AFAIK es lo más cerca que puedes llegar.

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

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

La respuesta corta es que no puedes. WndProc funciona al pasar mensajes a un HWND en un nivel de Win32. Las ventanas de WPF no tienen HWND y, por lo tanto, no pueden participar en los mensajes de WndProc. El bucle de mensajes de WPF base se coloca encima de WndProc pero los abstrae de la lógica principal de WPF.

Puede usar un HWndHost y obtener un WndProc para ello. Sin embargo, esto es casi seguro que no es lo que quieres hacer. Para la mayoría de los propósitos, WPF no opera en HWND y WndProc. Su solución casi seguramente se basa en realizar un cambio en WPF no en WndProc.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top