Pergunta

Finding WPF uma curva de aprendizagem.

Em boa ol' Windows Forms, eu tinha acabado de substituir WndProc, e começar a lidar com mensagens como eles entraram.

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

Foi útil?

Solução

Na verdade, tanto quanto eu entendo essa coisa um é realmente possível no WPF usando HwndSource e HwndSourceHook. Consulte esta discussão 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 tenho certeza por que você gostaria de 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 design ea natureza da API é muito diferente em WPF de WinForms, então eu sugiro que você acabou de se familiarizar com WPF mais para ver exatamente o por não existe equivalente de WndProc.

Outras dicas

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

Exemplo de utilizar 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 retirado do excelente blog post: Usando um WndProc personalizada no WPF aplicativos por 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 você não se importa referenciar WinForms, você pode usar uma solução mais orientada para o MVVM que não faz serviço de par com a vista. Você precisa criar e inicializar um System.Windows.Forms.NativeWindow que é uma janela leve que pode receber mensagens.

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 se inscrever para mensagens que você está interessado e, em seguida, substituir WndProc para processá-los:

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

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

Mais sobre isso pode ser lido aqui

Existem maneiras de mensagens puxadores com um WndProc em WPF (por exemplo, usando um HwndSource, etc.), mas geralmente essas técnicas são reservados para interoperabilidade com mensagens que não podem ser diretamente manipulados através WPF. A maioria dos controles WPF não são sequer janelas no Win32 (e por extensão Windows.Forms) sentido, para que eles não terão wndProcs.

Você pode anexar a classe da classe built-in Win32 dos SystemEvents ':

using Microsoft.Win32;

em uma classe de janela 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 não opera em wndProcs tipo WinForms

Você pode hospedar um HwndHost em um elemento WPF apropriado, em seguida, substituir wndproc do HwndHost, mas AFAIK que é tão perto que você vai conseguir.

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

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

A resposta curta é que você não pode. WndProc funciona por meio de mensagens para um HWND em um nível Win32. janelas WPF não têm HWND e, portanto, não podem participar em mensagens de WndProc. O loop de mensagem base WPF faz sentar em cima de WndProc mas abstrai-los longe da lógica WPF núcleo.

Você pode usar um HwndHost e chegar a um WndProc para ele. No entanto, este não é certamente o que você quer fazer. Para a maioria dos fins, WPF não opera em HWND e WndProc. Sua solução quase certamente se baseia em fazer uma mudança em WPF não em WndProc.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top