WPF에서 WNDProc 메시지를 처리하는 방법은 무엇입니까?
문제
가파른 학습 곡선을 찾는다.
좋은 ol 'windows 양식에서는 그냥 무시합니다 WndProc
, 메시지가 들어 오면서 메시지를 다루기 시작하십시오.
누군가 WPF에서 같은 일을 달성하는 방법의 예를 보여줄 수 있습니까?
해결책
실제로, 내가 이해하는 한, WPF를 사용하는 것은 실제로 가능합니다. HwndSource
그리고 HwndSourceHook
. 보다 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 메시징 메시지를 처리하려는 이유는 확실하지 않습니다 (다른 WinForms 앱으로 작업하기위한 가장 확실한 Interop이 아닌 한). 디자인 이데올로기와 API의 특성은 Winforms와 WPF에서 매우 다르므로 WPF를 더 잘 알고 있어야합니다. 왜 WNDPROC와 동등한 것은 없습니다.
다른 팁
당신은 이것을 통해 이것을 할 수 있습니다 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;
}
}
}
훌륭한 블로그 게시물에서 완전히 가져 왔습니다. Steve Rands의 WPF 앱에서 사용자 정의 WNDPROC 사용
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를 참조하지 않으면 서비스를 제공하지 않는 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 참조를 포함해야한다는 것입니다. 그렇지 않으면 이것은 매우 캡슐화 된 솔루션입니다.
이것에 대한 자세한 내용은 읽을 수 있습니다 여기
WPF (예 : HWNDSOURCE 등 사용)에서 WNDPROC로 메시지를 처리하는 방법이 있지만 일반적으로 해당 기술은 WPF를 통해 직접 처리 할 수없는 메시지와 연결되어 있습니다. 대부분의 WPF 컨트롤은 Win32 (및 Extension Windows.forms)의 Windows가 아니므로 WNDProc가 없습니다.
내장 된 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();
}
}
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
짧은 대답은 당신이 할 수 없다는 것입니다. WNDPROC는 Win32 레벨에서 HWND로 메시지를 전달하여 작동합니다. WPF Windows에는 HWND가 없으므로 WNDPROC 메시지에 참여할 수 없습니다. 기본 WPF 메시지 루프는 WNDPROC 위에 놓여 있지만 핵심 WPF 로직에서 멀리 떨어져 있습니다.
당신은 hwndhost를 사용하고 그것을 위해 wndproc에 갈 수 있습니다. 그러나 이것은 거의 확실히 당신이하고 싶은 일이 아닙니다. 대부분의 목적을 위해 WPF는 HWND 및 WNDPROC에서 작동하지 않습니다. 귀하의 솔루션은 거의 확실히 WNDPROC가 아닌 WPF를 변경하는 데 의존합니다.