Нахождение WPF крутой кривой обучения.
В хороших версиях Windows Forms я просто переопределял WndProc
и начал обрабатывать сообщения, когда они вошли.
Может ли кто-нибудь показать мне пример того, как добиться того же в WPF?
Нахождение WPF крутой кривой обучения.
В хороших версиях Windows Forms я просто переопределял 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;
}
Теперь я не совсем уверен, почему вы хотите обрабатывать сообщения Windows Messaging в приложении WPF (если это не самая очевидная форма взаимодействия для работы с другим приложением WinForms). Дизайнерская идеология и характер API очень различны в WPF от WinForms, поэтому я бы предложил вам просто ознакомиться с WPF, чтобы узнать, почему нет эквивалента WndProc.
Вы можете сделать это через System.Windows.Interop
имен 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;
}
}
}
Полностью взято из превосходного сообщения в блоге: использование пользовательского 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;
}
Вы можете найти другое объяснение для прикрепления к WndProc здесь.
Существуют способы обработки сообщений с помощью WndProc в WPF (например, с использованием HwndSource и т.д.), но в целом эти методы зарезервированы для взаимодействия с сообщениями, которые нельзя напрямую обрабатывать через WPF. Большинство элементов управления WPF не являются даже окнами в Win32 (и с расширением Windows.Forms), поэтому у них не будет WndProcs.
Если вы не возражаете ссылаться на 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, но в противном случае это очень инкапсулированное решение.
Подробнее об этом можно прочитать здесь
Вы можете подключиться к классу "SystemEvents" встроенного класса Win32:
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
Вы можете разместить HWndHost в соответствующем элементе WPF, а затем переопределить Hwndhost wndproc, но AFAIK, который как можно ближе к вам.
http://msdn.microsoft.com/en-us/library/ms742522.aspx
http://blogs.msdn.com/nickkramer/archive/2006/03/18/554235.aspx
Короткий ответ: вы не можете. WndProc работает, передавая сообщения HWND на уровне Win32. Окна WPF не имеют HWND и, следовательно, не могут участвовать в сообщениях WndProc. Базовый цикл сообщений WPF сидит поверх WndProc, но он абстрагирует их от основной логики WPF.
Вы можете использовать HWndHost и получить для него WndProc. Однако это почти наверняка не то, что вы хотите сделать. Для большинства целей WPF не работает с HWND и WndProc. Ваше решение почти наверняка зависит от внесения изменений в WPF не в WndProc.