Set the position of a WPF window relative to a non-WPF window

Source: Internet
Author: User

In the previous Post, we pointed out a BUG in the javaswinterophelper class of WPF: using the Owner attribute of javaswinterophelper cannot set the Owner attribute of the WPF window to a handle of a non-WPF window.

In less than one day after my Post posts, I provided a perfect solution for this BUG on the Blog of the WPF SDK. Since WindowStartupLocation. CenterOwner is set differently to change the window location. Then we use WindowStartupLocation. Manual to manually calculate the location of the window. The rough code is as follows:

Using System. Windows;
Using System. Windows. Interop; // WindowInteropHelper

...

// Instantiate the owned WPF window
Window cw = new Window ();

// Set the owned WPF window's owner with the non-WPF owner window
IntPtr owner?whandle = ...;
 
// Set the owned WPF window's owner with the non-WPF owner window

Export winterophelper helper = new export winterophelper (cw );
Helper. Owner = ownerWindowHandle;

// Manually calculate Top/Left to appear centered
Int nonWPFOwnerLeft =...; // Get non-WPF owner's Left
Int nonWPFOwnerWidth =...; // Get non-WPF owner's Width
Int nonWPFOwnerTop =...; // Get non-WPF owner's Top
Int nonWPFOwnerHeight =...; // Get non-WPF owner's Height

Cw. WindowStartupLocation = WindowStartupLocation. Manual;
Cw. Left = nonWPFOwnerLeft + (nonWPFOwnerWidth-cw. Width)/2;
Cw. Top = nonWPFOwnerTop + (nonWPFOwnerHeight-cw. Height)/2;

// Show the owned WPF window
Cw. Show ();

In theory, there is no problem with this code? However, WPF supports device independence. Therefore, the DPI may fail to work properly in some cases without the WPF Owner window. To solve this problem, you can use the HwndSource class to independently calculate the device location of the window:

Using System. Windows; // Window, WindowStartupLocation, Point
Using System. Windows. Interop; // export winterophelper, HwndSource
Using System. Windows. Media; // Matrix

...

// Instantiate the owned WPF window
CenteredWindow cw = new CenteredWindow ();

// Get the handle to the non-WPF owner window
IntPtr owner1_whandle =...; // Get hWnd for non-WPF window
 
// Set the owned WPF window's owner with the non-WPF owner window
Export winterophelper helper = new export winterophelper (cw );
Helper. Owner = ownerWindowHandle;
 

// Center window
// Note-Need to use HwndSource to get handle to WPF owned window,
// And the handle only exists when SourceInitialized has been
// Raised

Cw. SourceInitialized + = delegate
{
// Get WPF size and location for non-WPF owner window
Int nonWPFOwnerLeft =...; // Get non-WPF owner's Left
Int nonWPFOwnerWidth =...; // Get non-WPF owner's Width
Int nonWPFOwnerTop =...; // Get non-WPF owner's Top
Int nonWPFOwnerHeight =...; // Get non-WPF owner's Height

// Get transform matrix to transform non-WPF owner window
// Size and location units into device-independent WPF
// Size and location units

HwndSource source = HwndSource. FromHwnd (helper. Handle );
If (source = null) return;
Matrix matrix = source. CompositionTarget. TransformFromDevice;
Point ownerWPFSize = matrix. Transform (
New Point (nonWPFOwnerWidth, nonWPFOwnerHeight ));
Point ownerWPFPosition = matrix. Transform (
New Point (nonWPFOwnerLeft, nonWPFOwnerTop ));

// Center WPF window
Cw. WindowStartupLocation = WindowStartupLocation. Manual;
Cw. Left = ownerWPFPosition. X + (ownerWPFSize. X-cw. Width)/2;
Cw. Top = ownerWPFPosition. Y + (ownerWPFSize. Y-cw. Height)/2;

};

// Show WPF owned window
Cw. Show ();

Note the use of HwndSource in the above Code. This class requires a window handle, so its code is executed in a SourceInitialized event Delegate function.

Finally, in addition to the above method, we can also implement it using Win32 API functions. In the CWindow class of ATL, there is such a function, which I put directly below, if you are interested, refer to the implementation principles below:

 

BOOL CenterWindow (HWND hWndCenter = NULL) throw ()
...{
ATLASSERT (: IsWindow (m_hWnd ));

// Determine owner window to center against
DWORD dwStyle = GetStyle ();
If (hWndCenter = NULL)
...{
If (dwStyle & WS_CHILD)
HWndCenter =: GetParent (m_hWnd );
Else
HWndCenter =: GetWindow (m_hWnd, GW_OWNER );
}

// Get coordinates of the window relative to its parent
RECT rcDlg;
: GetWindowRect (m_hWnd, & rcDlg );
RECT rcArea;
RECT rcCenter;
HWND hWndParent;
If (! (DwStyle & WS_CHILD ))
...{
// Don't center against invisible or minimized windows
If (hWndCenter! = NULL)
...{
DWORD dwStyleCenter =: GetWindowLong (hWndCenter, GWL_STYLE );
If (! (DwStyleCenter & WS_VISIBLE) | (dwStyleCenter & WS_MINIMIZE ))
HWndCenter = NULL;
}

// Center within screen coordinates
: SystemParametersInfo (SPI_GETWORKAREA, NULL, & rcArea, NULL );
If (hWndCenter = NULL)
RcCenter = rcArea;
Else
: GetWindowRect (hWndCenter, & rcCenter );
}
Else
...{
// Center within parent client coordinates
HWndParent =: GetParent (m_hWnd );
ATLASSERT (: IsWindow (hWndParent ));

: GetClientRect (hWndParent, & rcArea );
ATLASSERT (: IsWindow (hWndCenter ));
: GetClientRect (hWndCenter, & rcCenter );
: MapWindowPoints (hWndCenter, hWndParent, (POINT *) & rcCenter, 2 );
}

Int DlgWidth = rcDlg. right-rcDlg. left;
Int DlgHeight = rcDlg. bottom-rcDlg. top;

// Find dialog's upper left based on rcCenter
Int xLeft = (rcCenter. left + rcCenter. right)/2-DlgWidth/2;
Int yTop = (rcCenter. top + rcCenter. bottom)/2-DlgHeight/2;

// If the dialog is outside the screen, move it inside
If (xLeft <rcArea. left)
XLeft = rcArea. left;
Else if (xLeft + DlgWidth> rcArea. right)
XLeft = rcArea. right-DlgWidth;

If (yTop <rcArea. top)
YTop = rcArea. top;
Else if (yTop + DlgHeight> rcArea. bottom)
YTop = rcArea. bottom-DlgHeight;

// Map screen coordinates to child coordinates
Return: SetWindowPos (m_hWnd, NULL, xLeft, yTop,-1,-1,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.