Yanıtlar:
Aslında, anladığım kadarıyla böyle bir şey WPF'de HwndSource
ve kullanarak gerçekten mümkün HwndSourceHook
. Örnek olarak MSDN'deki bu ileti dizisine bakın . (İlgili kod aşağıdadır)
// '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;
}
Şimdi, neden bir WPF uygulamasında Windows Mesajlaşma mesajlarını işlemek isteyeceğinizden tam olarak emin değilim (başka bir WinForms uygulamasıyla çalışmak için en belirgin birlikte çalışma biçimi değilse). API'nin tasarım ideolojisi ve doğası, WPF'de WinForms'tan çok farklıdır, bu nedenle tam olarak neden WndProc'un eşdeğeri olmadığını görmek için WPF'ye daha fazla aşina olmanızı öneririm .
WM_MOUSEWHEEL
örneğin, bu mesajları güvenilir bir şekilde yakalamanın tek yolu WndProc
, bir WPF penceresine eklemekti . Bu benim için işe yaradı, oysa görevli MouseWheelEventHandler
beklendiği gibi çalışmadı. Güvenilir davranış elde etmek için doğru şekilde sıralanan doğru WPF takyonlarını alamadım MouseWheelEventHandler
, bu nedenle WndProc
.
Bunu, System.Windows.Interop
adlandırılmış bir sınıfı içeren ad alanı aracılığıyla yapabilirsiniz HwndSource
.
Bunu kullanma örneği
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;
}
}
}
Tamamen mükemmel blog gönderisinden alınmıştır: Steve Rands tarafından WPF uygulamalarında özel bir WndProc kullanma
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;
}
WinForms'a başvurmaktan çekinmiyorsanız, servisi görünümle birleştirmeyen daha MVVM odaklı bir çözüm kullanabilirsiniz. İletileri alabilen hafif bir pencere olan System.Windows.Forms.NativeWindow oluşturmanız ve başlatmanız gerekir.
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;
}
}
İlgilendiğiniz mesajlara kaydolmak için SpongeHandle'ı kullanın ve ardından bunları işlemek için WndProc'u geçersiz kılın:
public class WindowsMessageListenerService : WinApiServiceBase
{
protected override void WndProc(Message message)
{
Debug.WriteLine(message.msg);
}
}
Tek dezavantajı, System.Windows.Forms referansını dahil etmeniz gerektiğidir, ancak aksi takdirde bu çok kapsüllenmiş bir çözümdür.
Bununla ilgili daha fazla bilgiyi buradan okuyabilirsiniz
Davranışları kullanarak WindProc'u geçersiz kılmaya ilişkin bir bağlantı: http://10rem.net/blog/2010/01/09/a-wpf-behavior-for-window-resize-events-in-net-35
[Düzenleme: hiç olmamasından iyidir geç] Aşağıda, yukarıdaki bağlantıya dayalı uygulamam verilmiştir. Bunu tekrar ziyaret etsem de AddHook uygulamalarını daha çok beğeniyorum. Ben buna geçebilirim.
Benim durumumda, pencerenin ne zaman yeniden boyutlandırıldığını ve birkaç başka şeyi bilmek istedim. Bu uygulama Window xaml'e bağlanır ve olayları gönderir.
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...
cevap aldım: yukarıdaki gibi.
Yerleşik Win32 sınıfının 'SystemEvents' sınıfına ekleyebilirsiniz:
using Microsoft.Win32;
bir WPF pencere sınıfında:
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'de bir WndProc ile mesajları işlemenin yolları vardır (örneğin, bir HwndSource kullanarak, vb.), Ancak genellikle bu teknikler, WPF aracılığıyla doğrudan işlenemeyen mesajlarla birlikte çalışmak için ayrılmıştır. Çoğu WPF denetimi Win32 (ve uzantı olarak Windows.Forms) anlamında pencere bile değildir, bu nedenle WndProcs'a sahip olmazlar.
WndProc
geçersiz kılmaya maruz kalmadığı doğru olsa da , özel olarak biçimlendirilmiş bir temsilciye bağlanabileceğiniz veya yoluyla System.Windows.Interop
bir HwndSource
nesne almanıza olanak tanır . Bu temsilci, bir Message nesnesiyle aynı bağımsız değişkenlerin çoğuna sahiptir . HwndSource.FromHwnd
PresentationSource.FromVisual(someForm) as HwndSource
WndProc
WPF, WinForms türü wndprocs üzerinde çalışmaz
Bir HWndHost'u uygun bir WPF öğesinde barındırabilir, ardından Hwndhost'un wndproc'unu geçersiz kılabilirsiniz, ancak AFAIK alacağınız kadar yakındır.
http://msdn.microsoft.com/en-us/library/ms742522.aspx
http://blogs.msdn.com/nickkramer/archive/2006/03/18/554235.aspx
Kısa cevap, yapamazsınız. WndProc, iletileri Win32 düzeyinde bir HWND'ye ileterek çalışır. WPF pencerelerinde HWND yoktur ve bu nedenle WndProc mesajlarına katılamaz. Temel WPF mesaj döngüsü WndProc'un üstüne oturur, ancak onları çekirdek WPF mantığından soyutlar.
Bir HWndHost kullanabilir ve bunun için bir WndProc'a girebilirsiniz. Ancak bu neredeyse kesinlikle yapmak istediğiniz şey değil. Çoğu amaç için, WPF, HWND ve WndProc üzerinde çalışmaz. Çözümünüz neredeyse kesinlikle WndProc'da değil, WPF'de bir değişiklik yapmaya dayanır.