如何在WPF中处理WndProc消息?

时间:2009-03-08 21:49:03

标签: c# wpf wndproc

寻找WPF陡峭的学习曲线。

在好的Windows窗体中,我只是覆盖WndProc,并在邮件进入时开始处理。

有人能告诉我如何在WPF中实现同样的事情吗?

8 个答案:

答案 0 :(得分:127)

您可以通过包含名为System.Windows.Interop的类的HwndSource命名空间来执行此操作。

使用此

的示例
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;
        }
    }
}

完全取自优秀的博文:Using a custom WndProc in WPF apps by Steve Rands

答案 1 :(得分:55)

实际上,据我所知,在使用HwndSourceHwndSourceHook的WPF中确实可以做到这样的事情。请参阅this thread on MSDN作为示例。 (相关代码包括在内)

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

现在,我不太清楚你为什么要在WPF应用程序中处理Windows Messaging消息(除非它是使用另一个WinForms应用程序的最明显的互操作形式)。在WPF和WinForms中,API的设计思想和性质是非常不同的,所以我建议你更熟悉WPF,看看为什么没有WndProc的等价物。

答案 2 :(得分:14)

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

答案 3 :(得分:1)

如果您不介意引用WinForms,您可以使用更多面向MVVM的解决方案,该解决方案不会将服务与视图耦合。您需要创建并初始化System.Windows.Forms.NativeWindow,它是一个可以接收消息的轻量级窗口。

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

使用SpongeHandle注册您感兴趣的邮件,然后覆盖WndProc来处理它们:

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

唯一的缺点是你必须包含System.Windows.Forms参考,否则这是一个非常封装的解决方案。

有关详情,请参阅here

答案 4 :(得分:0)

有一些方法可以在WPF中使用WndProc处理消息(例如,使用HwndSource等),但通常这些技术保留用于与无法通过WPF直接处理的消息互操作。大多数WPF控件甚至不是Win32中的窗口(以及扩展名为Windows.Forms),因此它们不会有WndProcs。

答案 5 :(得分:0)

您可以附加到&#39; SystemEvents&#39;内置Win32类的类:

using Microsoft.Win32;

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

答案 6 :(得分:-3)

WPF不能在WinForms类型的wndprocs上运行

你可以在一个合适的WPF元素中托管一个HWndHost然后覆盖Hwndhost的wndproc,但是AFAIK就像你将要获得的那样接近。

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

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

答案 7 :(得分:-10)

简短的回答是你不能。 WndProc的工作方式是将消息传递给Win32级别的HWND。 WPF窗口没有HWND,因此无法参与WndProc消息。基本WPF消息循环确实位于WndProc之上,但它将它们从核心WPF逻辑中抽象出来。

您可以使用HWndHost并获取WndProc。然而,这几乎肯定不是你想要做的。出于大多数目的,WPF不在HWND和WndProc上运行。您的解决方案几乎肯定依赖于在WPF中进行更改,而不是在WndProc中。