WPF에서의 WndProc 메시지 처리 방법
Windows Forms windows 、 in 、WndProc메시지 수신 시 처리를 시작합니다.
WPF에서 같은 것을 실현하는 방법의 예를 보여 주실 수 있습니까?
이 조작은,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 사용
실제로 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 Messaging 메시지를 처리하려는 이유를 잘 모르겠습니다(다른 WinForms 어플리케이션에서 작업할 때 가장 명백한 형태의 interop이 아닌 경우).WPF와 WinForms의 디자인 이념과 API의 성격은 크게 다르기 때문에 WndProc와 동등한 것이 없는 이유를 정확히 알기 위해 WPF에 대해 좀 더 숙지해 둘 것을 제안합니다.
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 지향적인 솔루션을 사용할 수 있습니다.시스템을 만들고 초기화해야 합니다.창문들.Forms.Native Window 메시지를 수신할 수 있는 경량 창입니다.
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);
}
}
유일한 단점은 시스템을 포함해야 한다는 것입니다.창문들.참조를 형성하지만 그렇지 않으면 매우 캡슐화된 솔루션입니다.
다음은 동작을 사용하여 WindProc를 재정의하는 링크입니다.http://10rem.net/blog/2010/01/09/a-wpf-behavior-for-window-resize-events-in-net-35
[편집: 늦게 하는 것이 안 하는 것보다 낫다]상기 링크에 근거한 실장을 이하에 나타냅니다.이것을 재검토하고 있습니다만, 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>
내장 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에서 WndProc를 사용하여 메시지를 처리하는 방법(예를 들어 HwndSource 사용 등)이 있지만 일반적으로 이러한 기술은 WPF를 통해 직접 처리할 수 없는 메시지와의 상호 운용을 위해 예약되어 있습니다.대부분의 WPF 컨트롤은 Win32(및 확장 Windows)에서는 창이 아닙니다.WndProcs를 사용하지 않도록 양식)을 인식합니다.
WPF는 WinForms type 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 창에는 HWND가 없기 때문에 WndProc 메시지에 참여할 수 없습니다.기본 WPF 메시지루프는 WndProc 위에 있지만 핵심 WPF 로직에서 제외됩니다.
HWndHost를 사용하여 WndProc를 이용할 수 있습니다.그러나 이것은 거의 확실히 당신이 하고 싶은 일이 아니다.대부분의 경우 WPF는 HWND 및 WndProc에서는 동작하지 않습니다.고객의 솔루션은 WndProc가 아닌 WPF에서 변경을 가하는 것이 거의 확실합니다.
언급URL : https://stackoverflow.com/questions/624367/how-to-handle-wndproc-messages-in-wpf
'programing' 카테고리의 다른 글
| iOS에서 프로그램 방식으로 자체 전화 번호 가져오기 (0) | 2023.04.14 |
|---|---|
| 언와인드 세그를 프로그래밍 방식으로 실행하는 방법 (0) | 2023.04.14 |
| Excel의 셀을 보호하지만 VBA 스크립트에 의해 셀을 수정할 수 있습니다. (0) | 2023.04.14 |
| WPF에서 콤보박스 컨트롤에 열거형을 바인드하려면 어떻게 해야 합니까? (0) | 2023.04.09 |
| HSSF(Apache POI)를 사용하여 기존 Excel에서 두 줄 사이에 행을 삽입하는 방법 (0) | 2023.04.09 |