在Windows窗体中,我只需重写WndProc,并在消息传入时开始处理它们。有人能给我一个例子,说明如何在WPF中实现同样的事情?
WndProc
bnlyeluc1#
您可以通过System.Windows.Interop命名空间来完成此操作,该命名空间包含一个名为HwndSource的类。使用此选项的示例
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
e4yzc0pl2#
实际上,据我所知,在WPF中使用HwndSource和HwndSourceHook确实可以做到这一点,以this thread on MSDN为例。(下面包含相关代码)
HwndSourceHook
// '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中API的设计思想和性质与WinForms中非常不同,所以我建议您进一步熟悉WPF,以确切地了解 * 为什么 * 没有WndProc的等价物。
f2uvfpb93#
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; }
evrscar24#
如果你不介意引用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引用,但除此之外,这是一个非常封装的解决方案。
92vpleto5#
以下是有关使用行为覆盖WindProc的链接:http://10rem.net/blog/2010/01/09/a-wpf-behavior-for-window-resize-events-in-net-35[Edit:迟做总比不做好]下面是我基于上面链接的实现。虽然重新访问了这个,但我更喜欢AddHook实现。我可能会切换到那个。在我的例子中,我想知道窗口什么时候被调整大小,以及其他一些事情。这个实现连接到Window xaml并发送事件。
using System; using System.Windows.Interactivity; using System.Windows; // For Window in behavior using System.Windows.Interop; // For Hwnd public class WindowResizeEvents : Behavior<Window> { public event EventHandler Resized; public event EventHandler Resizing; public event EventHandler Maximized; public event EventHandler Minimized; public event EventHandler Restored; public static DependencyProperty IsAppAskCloseProperty = DependencyProperty.RegisterAttached("IsAppAskClose", typeof(bool), typeof(WindowResizeEvents)); public Boolean IsAppAskClose { get { return (Boolean)this.GetValue(IsAppAskCloseProperty); } set { this.SetValue(IsAppAskCloseProperty, value); } } // called when the behavior is attached // hook the wndproc protected override void OnAttached() { base.OnAttached(); AssociatedObject.Loaded += (s, e) => { WireUpWndProc(); }; } // call when the behavior is detached // clean up our winproc hook protected override void OnDetaching() { RemoveWndProc(); base.OnDetaching(); } private HwndSourceHook _hook; private void WireUpWndProc() { HwndSource source = HwndSource.FromVisual(AssociatedObject) as HwndSource; if (source != null) { _hook = new HwndSourceHook(WndProc); source.AddHook(_hook); } } private void RemoveWndProc() { HwndSource source = HwndSource.FromVisual(AssociatedObject) as HwndSource; if (source != null) { source.RemoveHook(_hook); } } private const Int32 WM_EXITSIZEMOVE = 0x0232; private const Int32 WM_SIZING = 0x0214; private const Int32 WM_SIZE = 0x0005; private const Int32 SIZE_RESTORED = 0x0000; private const Int32 SIZE_MINIMIZED = 0x0001; private const Int32 SIZE_MAXIMIZED = 0x0002; private const Int32 SIZE_MAXSHOW = 0x0003; private const Int32 SIZE_MAXHIDE = 0x0004; private const Int32 WM_QUERYENDSESSION = 0x0011; private const Int32 ENDSESSION_CLOSEAPP = 0x1; private const Int32 WM_ENDSESSION = 0x0016; private IntPtr WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, ref Boolean handled) { IntPtr result = IntPtr.Zero; switch (msg) { case WM_SIZING: // sizing gets interactive resize OnResizing(); break; case WM_SIZE: // size gets minimize/maximize as well as final size { int param = wParam.ToInt32(); switch (param) { case SIZE_RESTORED: OnRestored(); break; case SIZE_MINIMIZED: OnMinimized(); break; case SIZE_MAXIMIZED: OnMaximized(); break; case SIZE_MAXSHOW: break; case SIZE_MAXHIDE: break; } } break; case WM_EXITSIZEMOVE: OnResized(); break; // Windows is requesting app to close. // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa376890%28v=vs.85%29.aspx. // Use the default response (yes). case WM_QUERYENDSESSION: IsAppAskClose = true; break; } return result; } private void OnResizing() { if (Resizing != null) Resizing(AssociatedObject, EventArgs.Empty); } private void OnResized() { if (Resized != null) Resized(AssociatedObject, EventArgs.Empty); } private void OnRestored() { if (Restored != null) Restored(AssociatedObject, EventArgs.Empty); } private void OnMinimized() { if (Minimized != null) Minimized(AssociatedObject, EventArgs.Empty); } private void OnMaximized() { if (Maximized != null) Maximized(AssociatedObject, EventArgs.Empty); } } <Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:behaviors="clr-namespace:RapidCoreConfigurator._Behaviors" Title="name" Height="500" Width="750" BorderBrush="Transparent"> <i:Interaction.Behaviors> <behaviors:WindowResizeEvents IsAppAskClose="{Binding IsRequestClose, Mode=OneWayToSource}" Resized="Window_Resized" Resizing="Window_Resizing" /> </i:Interaction.Behaviors> ... </Window>
p8h8hvxi6#
您可以附加到内置Win32类的“SystemEvents”类:
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(); } }
piok6c0g7#
在WPF中有一些方法可以使用WndProc处理消息(例如使用HwndSource等),但通常这些技术是为与不能直接通过WPF处理的消息进行互操作而保留的。大多数WPF控件甚至不是Win32(以及扩展为Windows.Forms)意义上的窗口,因此它们不会有WndProc。
axr492tv8#
WPF不能在WinForms类型的wndprocs上运行您可以在适当的WPF元素中托管HWndHost,然后重写Hwndhost的wndproc,但AFAIK是您最接近的方法。http://msdn.microsoft.com/en-us/library/ms742522.aspxhttp://blogs.msdn.com/nickkramer/archive/2006/03/18/554235.aspx
hgtggwj09#
简单地说,你不能。WndProc通过将消息传递到Win32级别上的HWND来工作。WPF窗口没有HWND,因此不能参与WndProc消息。基本WPF消息循环确实位于WndProc之上,但它将它们从核心WPF逻辑中抽象出来。您可以使用HWndHost并为其获取WndProc。但是,这几乎肯定不是您想要做的。对于大多数用途,WPF不在HWND和WndProc上操作。您的解决方案几乎肯定依赖于在WPF中而不是在WndProc中进行更改。
9条答案
按热度按时间bnlyeluc1#
您可以通过
System.Windows.Interop
命名空间来完成此操作,该命名空间包含一个名为HwndSource
的类。使用此选项的示例
完全取自优秀的博客文章:Using a custom WndProc in WPF apps by Steve Rands
e4yzc0pl2#
实际上,据我所知,在WPF中使用
HwndSource
和HwndSourceHook
确实可以做到这一点,以this thread on MSDN为例。(下面包含相关代码)现在,我不太清楚为什么您希望在WPF应用程序中处理Windows Messaging消息(除非它是与另一个WinForms应用程序一起工作的最明显的互操作形式)。WPF中API的设计思想和性质与WinForms中非常不同,所以我建议您进一步熟悉WPF,以确切地了解 * 为什么 * 没有WndProc的等价物。
f2uvfpb93#
evrscar24#
如果你不介意引用WinForms,你可以使用一个更面向MVVM的解决方案,它不将服务与视图耦合。你需要创建并初始化一个System.Windows.Forms.NativeWindow,它是一个可以接收消息的轻量级窗口。
使用SpongeHandle注册您感兴趣的邮件,然后重写WndProc以处理它们:
唯一的缺点是必须包含System.Windows.Forms引用,但除此之外,这是一个非常封装的解决方案。
92vpleto5#
以下是有关使用行为覆盖WindProc的链接:http://10rem.net/blog/2010/01/09/a-wpf-behavior-for-window-resize-events-in-net-35
[Edit:迟做总比不做好]下面是我基于上面链接的实现。虽然重新访问了这个,但我更喜欢AddHook实现。我可能会切换到那个。
在我的例子中,我想知道窗口什么时候被调整大小,以及其他一些事情。这个实现连接到Window xaml并发送事件。
p8h8hvxi6#
您可以附加到内置Win32类的“SystemEvents”类:
在WPF窗口类中:
piok6c0g7#
在WPF中有一些方法可以使用WndProc处理消息(例如使用HwndSource等),但通常这些技术是为与不能直接通过WPF处理的消息进行互操作而保留的。大多数WPF控件甚至不是Win32(以及扩展为Windows.Forms)意义上的窗口,因此它们不会有WndProc。
axr492tv8#
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
hgtggwj09#
简单地说,你不能。WndProc通过将消息传递到Win32级别上的HWND来工作。WPF窗口没有HWND,因此不能参与WndProc消息。基本WPF消息循环确实位于WndProc之上,但它将它们从核心WPF逻辑中抽象出来。
您可以使用HWndHost并为其获取WndProc。但是,这几乎肯定不是您想要做的。对于大多数用途,WPF不在HWND和WndProc上操作。您的解决方案几乎肯定依赖于在WPF中而不是在WndProc中进行更改。