3

I'm writing a custom Wpf control and I need to grab a reference to the containing window's HwndSource at the earliest possible time. This would be 1) in the constructor of my control if possible or 2) at the point when the control is added to the display hierarchy.

How can I detect when/if the HwndSource is available? I plan to acquire a reference using code such as the following:

var source = HwndSource.FromVisual(this) as HwndSource;
H.B.
  • 166,899
  • 29
  • 327
  • 400
anthony
  • 40,424
  • 5
  • 55
  • 128

3 Answers3

4

You can use the PresentationSource's AddSourceChangedHandler method to listen for when the PS changes (HwndSource is a derived PS).

http://msdn.microsoft.com/en-us/library/system.windows.presentationsource.addsourcechangedhandler.aspx

AndrewS
  • 6,054
  • 24
  • 31
3

As far as I understand, WPF controls are not windows. Only the window in a wpf app has a hwnd.

From the msdn site:

"All WPF elements on the screen are ultimately backed by a HWND. When you create a WPF Window, WPF creates a top-level HWND, and uses an HwndSource to put the Window and its WPF content inside the HWND. The rest of your WPF content in the application shares that singular HWND. An exception is menus, combo box drop downs, and other pop-ups. These elements create their own top-level window, which is why a WPF menu can potentially go past the edge of the window HWND that contains it. When you use HwndHost to put an HWND inside WPF, WPF informs Win32 how to position the new child HWND relative to the WPF Window HWND."

For Win32 interoperability see the following link:

http://msdn.microsoft.com/en-us/library/ms742522.aspx

Edit: To enhance the answer to address the comment below:

In order to get the handle of the window that owns the hwnd, you can use the WindowInteropHelper class.

This example is also pulled from the MSDN documentation

in c#

WindowInteropHelper wih = new WindowInteropHelper(myDialog);
wih.Owner = ownerHwnd;
myDialog.ShowDialog();

in vb

Dim wih As New WindowInteropHelper(myDialog)
wih.Owner = ownerHwnd
myDialog.ShowDialog()

I hope this helps.

Rendition
  • 494
  • 2
  • 12
  • This is true, but at some point my control will be placed within an element on screen that is backed by an HWND, that is what I am trying to detect. – anthony Jun 09 '11 at 00:13
  • Hi. I hope the additional info in the text above answers your question. Good luck! – Rendition Jun 09 '11 at 07:44
2

I've always used the Window.SourceInitialized event to determine when the HWND (i.e. HwndSource) is ready for use. In your case, you'd probably need to add an override for the OnVisualParentChanged method. In your override, search up the visual tree for the associated Window (or use Window.GetWindow).

If the Window has a valid HWND, then you can just use it as-is. If not, then you'd have to subscribe to the SourceInitialized event. You could unhook from the SourceInitialized in your handler to ensure it is only called once.

This would not work if your control is hosted inside a Popup. In that case, you'd have to get a reference to the associated Popup and watch for the Opened event.

CodeNaked
  • 40,753
  • 6
  • 122
  • 148