Antworten:
Soweit ich weiß, ist so etwas in WPF tatsächlich mit HwndSource
und möglich HwndSourceHook
. Sehen Sie sich diesen Thread auf MSDN als Beispiel an. (Relevanter Code unten enthalten)
// '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;
}
Ich bin mir nicht ganz sicher, warum Sie Windows Messaging-Nachrichten in einer WPF-Anwendung verarbeiten möchten (es sei denn, dies ist die offensichtlichste Form der Interop-Funktion für die Arbeit mit einer anderen WinForms-App). Die Designideologie und die Art der API unterscheiden sich in WPF stark von WinForms. Ich würde daher empfehlen, dass Sie sich nur mit WPF vertraut machen, um genau zu sehen, warum es kein Äquivalent zu WndProc gibt.
WM_MOUSEWHEEL
Die einzige Möglichkeit, diese Nachrichten zuverlässig abzufangen, bestand beispielsweise darin, WndProc
sie einem WPF-Fenster hinzuzufügen . Das hat bei mir funktioniert, während der Beamte MouseWheelEventHandler
einfach nicht wie erwartet funktioniert hat. Ich war nicht in der Lage, die richtigen WPF-Tachyonen genau richtig auszurichten, um ein zuverlässiges Verhalten zu MouseWheelEventHandler
erzielen, weshalb ein direkter Zugriff auf die erforderlich war WndProc
.
Sie können dies über den System.Windows.Interop
Namespace tun, der eine Klasse mit dem Namen enthält HwndSource
.
Beispiel für die Verwendung
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;
}
}
}
Vollständig aus dem ausgezeichneten Blog-Beitrag entnommen: Verwenden eines benutzerdefinierten WndProc in WPF-Apps von 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;
}
Wenn es Ihnen nichts ausmacht, auf WinForms zu verweisen, können Sie eine MVVM-orientierte Lösung verwenden, die den Dienst nicht mit der Ansicht koppelt. Sie müssen ein System.Windows.Forms.NativeWindow erstellen und initialisieren. Dies ist ein kompaktes Fenster, das Nachrichten empfangen kann.
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;
}
}
Verwenden Sie SpongeHandle, um sich für Nachrichten zu registrieren, an denen Sie interessiert sind, und überschreiben Sie dann WndProc, um sie zu verarbeiten:
public class WindowsMessageListenerService : WinApiServiceBase
{
protected override void WndProc(Message message)
{
Debug.WriteLine(message.msg);
}
}
Der einzige Nachteil ist, dass Sie die System.Windows.Forms-Referenz einschließen müssen, ansonsten ist dies eine sehr gekapselte Lösung.
Mehr dazu lesen Sie hier
Hier ist ein Link zum Überschreiben von WindProc mithilfe von Verhalten: http://10rem.net/blog/2010/01/09/a-wpf-behavior-for-window-resize-events-in-net-35
[Bearbeiten: besser spät als nie] Unten ist meine Implementierung basierend auf dem obigen Link. Obwohl ich das noch einmal besuche, mag ich die AddHook-Implementierungen besser. Ich könnte dazu wechseln.
In meinem Fall wollte ich wissen, wann die Größe des Fensters geändert wurde und ein paar andere Dinge. Diese Implementierung wird mit dem Fenster xaml verbunden und sendet Ereignisse.
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>
Here is a link...
Antworten wie oben.
Sie können an die 'SystemEvents'-Klasse der integrierten Win32-Klasse anhängen:
using Microsoft.Win32;
in einer WPF-Fensterklasse:
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();
}
}
Es gibt Möglichkeiten, Nachrichten mit einem WndProc in WPF zu verarbeiten (z. B. mithilfe einer HwndSource usw.). Im Allgemeinen sind diese Techniken jedoch für die Interaktion mit Nachrichten reserviert, die nicht direkt über WPF verarbeitet werden können. Die meisten WPF-Steuerelemente sind nicht einmal Windows im Sinne von Win32 (und im weiteren Sinne Windows.Forms), daher verfügen sie nicht über WndProcs.
WndProc
Überschreibung ausgesetzt. Mit dieser Option System.Windows.Interop
können Sie jedoch ein HwndSource
Objekt über HwndSource.FromHwnd
oder abrufen, an das Sie PresentationSource.FromVisual(someForm) as HwndSource
einen speziell strukturierten Delegaten binden können. Dieser Delegat hat viele der gleichen Argumente wie ein WndProc
Nachrichtenobjekt.
WPF funktioniert nicht mit WinForms-Typ wndprocs
Sie können einen HWndHost in einem geeigneten WPF-Element hosten und dann den wndproc des Hwndhost überschreiben, aber AFAIK ist so nah wie möglich.
http://msdn.microsoft.com/en-us/library/ms742522.aspx
http://blogs.msdn.com/nickkramer/archive/2006/03/18/554235.aspx
Die kurze Antwort lautet: Sie können nicht. WndProc übergibt Nachrichten auf Win32-Ebene an einen HWND. WPF-Fenster haben kein HWND und können daher nicht an WndProc-Nachrichten teilnehmen. Die Basis-WPF-Nachrichtenschleife befindet sich zwar über WndProc, abstrahiert sie jedoch von der WPF-Kernlogik.
Sie können einen HWndHost verwenden und einen WndProc dafür erhalten. Dies ist jedoch mit ziemlicher Sicherheit nicht das, was Sie tun möchten. In den meisten Fällen arbeitet WPF nicht mit HWND und WndProc. Ihre Lösung basiert mit ziemlicher Sicherheit auf einer Änderung in WPF, nicht in WndProc.