2009-03-08 8 views
89

WPF को एक सीधी सीखने की वक्र ढूँढना।WPF में WndProc संदेशों को कैसे प्रबंधित करें?

अच्छा ol 'विण्डोज़ फॉर्म्स में, मैं सिर्फ WndProc ओवरराइड चाहते हैं, और संदेशों को संभालने के शुरू के रूप में वे में आया था।

कोई मुझे कैसे WPF में एक ही बात को प्राप्त करने का एक उदाहरण दिखा सकते हैं?

उत्तर

45

दरअसल, जहां तक ​​मैं समझता हूं कि WP12 में HwndSource और HwndSourceHook का उपयोग करके वास्तव में ऐसी चीज संभव है। एक उदाहरण के रूप में this thread on 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 आवेदन में विंडोज संदेश संदेशों को संभालने के लिए चाहते हैं (जब तक यह एक और WinForms अनुप्रयोग के साथ काम करने के लिए इंटरॉप का सबसे स्पष्ट रूप है नहीं कर रहा हूँ)। डिजाइन विचारधारा और एपीआई की प्रकृति WinForms से WPF में बहुत अलग है, इसलिए मैं सुझाव दूंगा कि आप केवल को देखने के लिए WPF के साथ स्वयं को परिचित करें क्यों WndProc के बराबर नहीं है।

+36

ठीक है, यूएसबी डिवाइस (डी) कनेक्ट घटनाएं इस संदेश लूप पर आ रही हैं, इसलिए यह जानना एक बुरी चीज नहीं है कि WPF – flq

+4

@Noldorin से कैसे जुड़ा हुआ है: क्या आप कृपया संदर्भ (लेख/पुस्तकें) प्रदान कर सकते हैं जो मदद कर सकते हैं मैं भाग को समझता हूं "डिजाइन विचारधारा और एपीआई की प्रकृति WinForms से WPF में बहुत अलग है, ... WndProc के बराबर क्यों नहीं है"? उदाहरण के लिए – atiyar

+1

'WM_MOUSEWHEEL', उन संदेशों को विश्वसनीय रूप से फंसाने का एकमात्र तरीका' डब्लूएनडीपीआरसी 'को एक डब्ल्यूपीएफ विंडो में जोड़कर था। यह मेरे लिए काम करता था, जबकि आधिकारिक 'MouseWheelEventHandler' बस अपेक्षा के अनुसार काम नहीं करता था। मैं 'डब्ल्यूडब्ल्यूपीआरओआर' के लिए सीधे पहुंच के लिए सही व्यवहार करने के लिए सही सही डब्ल्यूपीएफ टैचियन प्राप्त करने में असमर्थ था। –

-2

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

-8

संक्षिप्त उत्तर आप नहीं कर सकते है। WNDProc एक Win32 स्तर पर एक HWND को संदेश पास करके काम करता है। डब्ल्यूपीएफ विंडोज़ में कोई एचडब्ल्यूएनडी नहीं है और इसलिए WndProc संदेशों में भाग नहीं ले सकता है। बेस डब्ल्यूपीएफ संदेश लूप WndProc के शीर्ष पर बैठता है लेकिन यह उन्हें मूल WPF तर्क से दूर करता है।

आप एचडब्लूंडहोस्ट का उपयोग कर सकते हैं और इसके लिए एक डब्ल्यूडब्ल्यूप्रोक प्राप्त कर सकते हैं। हालांकि यह लगभग निश्चित रूप से नहीं है कि आप क्या करना चाहते हैं। अधिकांश उद्देश्यों के लिए, डब्ल्यूपीएफ एचडब्ल्यूएनडी और डब्ल्यूडब्ल्यूप्रोक पर काम नहीं करता है। आपका समाधान लगभग निश्चित रूप से WPF में परिवर्तन करने पर निर्भर करता है जो WndProc में नहीं है।

+7

"डब्ल्यूपीएफ विंडोज़ में कोई एचडब्ल्यूएनडी नहीं है" - यह बस असत्य है। –

0

डब्ल्यूपीएफ में एक डब्ल्यूडब्ल्यूप्रोक के साथ संदेशों को संभालने के तरीके हैं (उदाहरण के लिए एक एचडब्ल्यूडसोर्स इत्यादि का उपयोग करना), लेकिन आम तौर पर उन तकनीकों को उन संदेशों के साथ इंटरऑप के लिए आरक्षित किया जाता है जिन्हें सीधे WPF के माध्यम से नियंत्रित नहीं किया जा सकता है। अधिकांश WPF नियंत्रण Win32 (और एक्सटेंशन Windows.Forms द्वारा) में भी विंडोज़ नहीं हैं, इसलिए उनके पास WndProcs नहीं होगा।

14
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; 
} 
118

आप 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; 
     } 
    } 
} 

पूरी तरह से उत्कृष्ट ब्लॉग पोस्ट से लिया का उपयोग करने का

उदाहरण: Using a custom WndProc in WPF apps by Steve Rands (ध्यान दें, लिंक अब मान्य नहीं है)

इस साइट में अब नीचे है, लेकिन आप वेबैक से इसे देख सकते हैं इंजन: http://web.archive.org/web/20091019124817/http://www.steverands.com/2009/03/19/custom-wndproc-wpf-apps/

+0

लिंक टूटा हुआ है। क्या आप इसे ठीक कर सकते हैं? –

+1

@ मार्टिन, ऐसा इसलिए है क्योंकि स्टीव रैंड की वेबसाइट अब मौजूद नहीं है। एकमात्र फिक्स मैं सोच सकता हूं कि इसे हटाना है। मुझे लगता है कि यदि साइट भविष्य में वापस आती है तो यह अभी भी मूल्य जोड़ती है, इसलिए मैं इसे हटा नहीं रहा हूं - लेकिन अगर आप असहमत हैं तो संपादित करने के लिए स्वतंत्र महसूस करें। –

+0

क्या खिड़की के बिना WndProc संदेश प्राप्त करना संभव है? – Mo0gles

4

आप WndProc here से जुड़ने के लिए एक और स्पष्टीकरण पा सकते हैं।

0

यदि आपको WinForms का संदर्भ देने में कोई फर्क नहीं पड़ता है, तो आप एक और एमवीवीएम-उन्मुख समाधान का उपयोग कर सकते हैं जो दृश्य के साथ जोड़े की सेवा नहीं करता है। आपको 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 संदर्भ शामिल करने के लिए है कि है, लेकिन अन्यथा यह एक बहुत ही encapsulated समाधान है।

अधिक इस पर here पढ़ा जा सकता है

0

आप की '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(); 
    } 
} 
संबंधित मुद्दे