views:

1017

answers:

4

I have a WPF app which snaps to screen edges (I just set the .Top or .Left of the window if you're within 20 pixels of the screen edge), but I recently added some code provided by the WPF SDK Team to "mess" with the window chrome, and although it's working great (screenshot), it's causing the "snapto" to move the window unexpectedly (e.g.: it jumps to the left when it should be snapping straight down to the bottom)

I've narrowed it down to their handling of the WM_NCCALCSIZE ... which is really odd because they basically don't do anything, they just say they handle it, and return 0.

According to the documentation of WM_NCCALCSIZE, this should just result in the whole window being treated as client (having no non-client edge), but somehow it also means that whenever my snap-to code moves the window down to the bottom of the screen, it also moves left about 134 pixels ... (moving to the other edges has similar side effects) and as long as I hold the mouse to drag it, it flickers back and forth from where it's supposed to be. If I comment the WM_NCCALCSIZE handling out, the snap-to works the way it should (but the form doesn't look right).

I've tried everything I can thing of in the WM_NCCALCSIZE handler, but I can't stop it from jumping left ... and of course, WM_NCCALCSIZE only gets called when the window size changes, so I don't understand how it causes this in the first place!

P.S. If you want to actually see the code, it's already on CodePlex, in two files, look for _HandleNCCalcSize and OnWindowLocationChanged

A: 

What are wParam and lParam when the WM_NCCALCSIZE handler returns 0? The documentation says "if wParam is TRUE and an application returns zero, the old client area is preserved and is aligned with the upper-left corner of the new client area" which sounds like it might be what's happening to you.

jeffm
A: 

The wParam always seems to be TRUE (1) and lParam is a NCCALCSIZE_PARAMS ...

The intent is to do exactly what you said: to force the whole window to be "client" and then use the Vista DWM apis to extend the frame into the client area. I just don't see why it's moving so far to the left...

If I trace or breakpoint the HandleNCCalcSize method, when I resize the window (while it's on the edge so the snap-to fires), the NCCalcSize gets called twice: once where it should be, and then off to the left, where it ends up.

Jaykul
+1  A: 

The reason this happens is that handling the WM_NCCALCSIZE changes the overall size of the window ... but if you're moving the window, changing your position during WM_MOVE or WM_WINDOWPOSCHANGED (which corresponds to the WPF WindowPositionChanged event) causes another WM_NCCALCSIZE message ...

Making changes during WM_NCCALCSIZE (even just asserting that you handled the message) causes another call to WM_MOVE ... which puts you into a loop where the "FROM" part of the positionchanged message stays the same (making the window "jump" from where it started to the position you adjust it to during WM_MOVE over and over as it changes back after WM_NCCALCSIZE).

The Correct Way

What you have to do is to obey Raymond Chen and handle WM_WINDOWPOSCHANGING instead. It happens before these other messages, and that way they do not interfere with each other!

Jaykul
A: 

I am also facing similar issues with the WM_MOVE. I am also having an application with chrome window and the snapping feature handled with the Windows messaging. The problem I am having right now is that when the window gets loaded the WM_MOVE message is fired. This makes my window to be kind of a disabled state to recieve any more messages like LBUTTONDOWN and other messages. Any help from anyone?

Vijay BK
Yeah. Don't do window snapping in WM_MOVE ... do it in WM_WINDOWPOSCHANGING
Jaykul
Hey Jaykul, I tried the WM_WINDOWPOSCHANGING, but the screen flickers a lot (literally I cannot see the screen at all). Can you provide a sample code, so that I can see the difference.
Vijay BK