flicker when restraining one form to only move within the bounds ofanother

  • Thread starter Thread starter uncleSally
  • Start date Start date
U

uncleSally

* Note : I posted this message in the
microsoft.public.dotnet.framework.drawing forum, and Jeff Johnson
suggested I post it here, instead. I do think this is a more
appropriate forum, and I have deleted the post from the drawing forum.
I try and be very conscientous about never cross-posting.*

Hi,

Scenario :

1. Form1 : regular Windows Form. TopMost = false

2. Form2 : regular Windows Form with background color set to
TransparencyKey value so Form1 shows through where the background is
not covered by controls on it that have solid backgrounds and thus
appear opaque. TopMost = true

3. code in place in the Move event of Form2 to raise an Event to
Form1 that does the right thing to insure that moving Form2 outside
of Form1's client rectangle on the screen results in the position of
Form2 being moved back so it is within the bounds of Form1's client
rectangle.

I can do some nice things using independent forms which can have
their own TransparencyKeys set so the controls on them appear as
opaque with the form underneath showing through.

It's not that hard to write code that restrains the moving of these
independent forms to the current screen displayrect of the underlying
form, but :

As your code (that detects the moving topmost form is outside of the
underlying form) triggers to move the top form back into the
underlying form's client area, you can get some stutter/flicker
effects. If you drag fast, you can see the the dragged topmost form
outside the underlying form before it snaps back.

With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged).

Wonder if there's any hack that can be used to intercept a Move event
on Form2 before it's actually moved.
I've played with over-riding 'OnMove, in Form2, and can certainly
test in that over-ride whether the top Form's location is contained
within the form beneath it, but haven't found a way to stop a move
from happening by, for example, omitting the call to Base.OnMove(e)

thanks, Bill

p.s. yes, have played with various WindowStyles, Double-buffering,
etc. to no avail.
 
uncleSally said:
With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged).

Wonder if there's any hack that can be used to intercept a Move event
on Form2 before it's actually moved.
I've played with over-riding 'OnMove, in Form2, and can certainly
test in that over-ride whether the top Form's location is contained
within the form beneath it, but haven't found a way to stop a move
from happening by, for example, omitting the call to Base.OnMove(e)


I can't repro the flickering you describe, though two things you can try:

Find out window messages:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Debug.WriteLine(m.ToString)
MyBase.WndProc(m)
End Sub


This way I found WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE that you can handle to
recognize the start/end of a move operation.
(http://msdn.microsoft.com/en-us/library/ms632622(VS.85).aspx)

Dunno if this helps.


Armin
 
uncleSally said:
With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged).

Wonder if there's any hack that can be used to intercept a Move event
on Form2 before it's actually moved.
I've played with over-riding 'OnMove, in Form2, and can certainly
test in that over-ride whether the top Form's location is contained
within the form beneath it, but haven't found a way to stop a move
from happening by, for example, omitting the call to Base.OnMove(e)


I can't repro the flickering you describe, though two things you can try:

Find out window messages:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Debug.WriteLine(m.ToString)
MyBase.WndProc(m)
End Sub


This way I found WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE that you can handle to
recognize the start/end of a move operation.
(http://msdn.microsoft.com/en-us/library/ms632622(VS.85).aspx)

Dunno if this helps.


Armin
 
Thanks, Armin; I have been trying defining a WndProc, and intercepting
the following messages :

//msg=0x3 (WM_MOVE) hwnd=0x330562 wparam=0x0 lparam=0xcd0157
result=0x0
//msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x216 (WM_MOVING) hwnd=0x330562 wparam=0x9
lparam=0x558db48 result=0x0
//msg=0x231 (WM_ENTERSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0
//msg=0x232 (WM_EXITSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0

But setting the Message parameter of the WindowProc to IntPtr.Zero
and, of course, not calling the base.WndProc(m) for these messages
only, doesn't seem to have any effect at run-time on moving the window
for which the WndProc is installed.

Here's the WndProc I am using (C#) :

[System.Security.Permissions.PermissionSet
(System.Security.Permissions.SecurityAction.Demand, Name =
"FullTrust")]
protected override void WndProc(ref Message m)
{
// Console.WriteLine(m.ToString());

if (m.Msg == 0x3 || m.Msg == 0x46 || m.Msg ==0x47 || m.Msg
== 0x216 || m.Msg == 0x231 || m.Msg == 0x232)
{
m.Result = IntPtr.Zero;
// Console.WriteLine(m.ToString());
}
else
{
base.WndProc(ref m);
}
}

thanks, Bill
 
Thanks, Armin; I have been trying defining a WndProc, and intercepting
the following messages :

//msg=0x3 (WM_MOVE) hwnd=0x330562 wparam=0x0 lparam=0xcd0157
result=0x0
//msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x216 (WM_MOVING) hwnd=0x330562 wparam=0x9
lparam=0x558db48 result=0x0
//msg=0x231 (WM_ENTERSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0
//msg=0x232 (WM_EXITSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0

But setting the Message parameter of the WindowProc to IntPtr.Zero
and, of course, not calling the base.WndProc(m) for these messages
only, doesn't seem to have any effect at run-time on moving the window
for which the WndProc is installed.

Here's the WndProc I am using (C#) :

[System.Security.Permissions.PermissionSet
(System.Security.Permissions.SecurityAction.Demand, Name =
"FullTrust")]
protected override void WndProc(ref Message m)
{
// Console.WriteLine(m.ToString());

if (m.Msg == 0x3 || m.Msg == 0x46 || m.Msg ==0x47 || m.Msg
== 0x216 || m.Msg == 0x231 || m.Msg == 0x232)
{
m.Result = IntPtr.Zero;
// Console.WriteLine(m.ToString());
}
else
{
base.WndProc(ref m);
}
}

thanks, Bill
 
uncleSally said:
Thanks, Armin; I have been trying defining a WndProc, and intercepting
the following messages :

//msg=0x3 (WM_MOVE) hwnd=0x330562 wparam=0x0 lparam=0xcd0157
result=0x0
//msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x216 (WM_MOVING) hwnd=0x330562 wparam=0x9
lparam=0x558db48 result=0x0
//msg=0x231 (WM_ENTERSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0
//msg=0x232 (WM_EXITSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0

But setting the Message parameter of the WindowProc to IntPtr.Zero
and, of course, not calling the base.WndProc(m) for these messages
only, doesn't seem to have any effect at run-time on moving the window
for which the WndProc is installed.

Here's the WndProc I am using (C#) :

[System.Security.Permissions.PermissionSet
(System.Security.Permissions.SecurityAction.Demand, Name =
"FullTrust")]
protected override void WndProc(ref Message m)
{
// Console.WriteLine(m.ToString());

if (m.Msg == 0x3 || m.Msg == 0x46 || m.Msg ==0x47 || m.Msg
== 0x216 || m.Msg == 0x231 || m.Msg == 0x232)
{
m.Result = IntPtr.Zero;
// Console.WriteLine(m.ToString());
}
else
{
base.WndProc(ref m);
}
}

thanks, Bill

I'm not sure what you expect from supressing these messages. I was referring
to this:

"With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged)."

Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?


Armin
 
uncleSally said:
Thanks, Armin; I have been trying defining a WndProc, and intercepting
the following messages :

//msg=0x3 (WM_MOVE) hwnd=0x330562 wparam=0x0 lparam=0xcd0157
result=0x0
//msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x3904ea wparam=0x0
lparam=0x53edd1c result=0x0
//msg=0x216 (WM_MOVING) hwnd=0x330562 wparam=0x9
lparam=0x558db48 result=0x0
//msg=0x231 (WM_ENTERSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0
//msg=0x232 (WM_EXITSIZEMOVE) hwnd=0x330562 wparam=0x0
lparam=0x0 result=0x0

But setting the Message parameter of the WindowProc to IntPtr.Zero
and, of course, not calling the base.WndProc(m) for these messages
only, doesn't seem to have any effect at run-time on moving the window
for which the WndProc is installed.

Here's the WndProc I am using (C#) :

[System.Security.Permissions.PermissionSet
(System.Security.Permissions.SecurityAction.Demand, Name =
"FullTrust")]
protected override void WndProc(ref Message m)
{
// Console.WriteLine(m.ToString());

if (m.Msg == 0x3 || m.Msg == 0x46 || m.Msg ==0x47 || m.Msg
== 0x216 || m.Msg == 0x231 || m.Msg == 0x232)
{
m.Result = IntPtr.Zero;
// Console.WriteLine(m.ToString());
}
else
{
base.WndProc(ref m);
}
}

thanks, Bill

I'm not sure what you expect from supressing these messages. I was referring
to this:

"With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged)."

Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?


Armin
 
I'm not sure what you expect from supressing these messages. I was referring
to this:

"With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged)."

Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?

Thanks, Armin, again, for taking the time to reply !

I will try the strategy you suggest above, although this will allow
the moved-form to go outside the restraining form's boundaries (until
the point the mouse is let up which I assume will trigger
WM_EXITSIZEMOVE which is what I am trying to avoid).

best, Bill
 
I'm not sure what you expect from supressing these messages. I was referring
to this:

"With resizing you've got begin and end resize events you can play
with, but in terms of a form being moved using by dragging the
titlebar : you've got the Move event and the LocationChanged event
(haven't looked at RegionChanged)."

Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?

Thanks, Armin, again, for taking the time to reply !

I will try the strategy you suggest above, although this will allow
the moved-form to go outside the restraining form's boundaries (until
the point the mouse is let up which I assume will trigger
WM_EXITSIZEMOVE which is what I am trying to avoid).

best, Bill
 
Intercept the WM_MOVING (0x216) message and modify the RECT structure in
LParam before processing the message.
 
Intercept the WM_MOVING (0x216) message and modify the RECT structure in
LParam before processing the message.
 
Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?

[Edit of a previous message which has been removed]

< refresher : for those of you reading this, please remember we are
discussing moving independent forms over other independent forms, not
moving child Forms >

Thanks, Armin, again, for taking the time to reply !

For the case of dragging a Form with a TitleBar : Catching
WM_EXITSIZEMOVE only, and then adjusting the moved Form's position
certainly is a visual improvement ... but, at the cost of allowing the
moved Form to appear outside the boundaries of the Form you are trying
to restrain it to appear in ... until ... you release the mouse which
will trigger WM_EXITSIZEMOVE.

For the case of dragging a Form with no TitleBar : I have found if you
are using some little control to allow mouse-dragging the Form
around : the WM_EXITSIZEMOVE for the Form is never triggered in the
Form's WndProc : but there's an easy work-around : just check in the
MouseUp handler for the control you're using to move the Form around,
and restrain the moved Form within whatever boundaries there.

In both cases described above, the moved Form will appear outside the
boundaries of the Form until you release the mouse.

While these two scenarios are acceptable, for now, and are much better
than intercepting every WM_WINDOWPOSCHANGED or WM_WINDOWPOSCHANGING
event, I'd still like to think there's a way to create this "virtual
parenting" by another Form's boundaries without letting the moved Form
go outside the boundaries.

best, Bill
 
Therefore I thought you've been looking for an analogy, like a begin and end
move event. This is the WM_ENTERTSIZEMOVE and WM_EXITSIZEMOVE messages. By
handling the WM_EXITSIZEMOVE message instead of the Move event, you are able
to move the Form underneath only when moving the transparent form has
stopped. This would reduce flickering. Did I misunderstand?

[Edit of a previous message which has been removed]

< refresher : for those of you reading this, please remember we are
discussing moving independent forms over other independent forms, not
moving child Forms >

Thanks, Armin, again, for taking the time to reply !

For the case of dragging a Form with a TitleBar : Catching
WM_EXITSIZEMOVE only, and then adjusting the moved Form's position
certainly is a visual improvement ... but, at the cost of allowing the
moved Form to appear outside the boundaries of the Form you are trying
to restrain it to appear in ... until ... you release the mouse which
will trigger WM_EXITSIZEMOVE.

For the case of dragging a Form with no TitleBar : I have found if you
are using some little control to allow mouse-dragging the Form
around : the WM_EXITSIZEMOVE for the Form is never triggered in the
Form's WndProc : but there's an easy work-around : just check in the
MouseUp handler for the control you're using to move the Form around,
and restrain the moved Form within whatever boundaries there.

In both cases described above, the moved Form will appear outside the
boundaries of the Form until you release the mouse.

While these two scenarios are acceptable, for now, and are much better
than intercepting every WM_WINDOWPOSCHANGED or WM_WINDOWPOSCHANGING
event, I'd still like to think there's a way to create this "virtual
parenting" by another Form's boundaries without letting the moved Form
go outside the boundaries.

best, Bill
 
Mick Doherty wrote :
Intercept the WM_MOVING (0x216)  message and modify the RECT structure in
LParam before processing the message.

Thanks Mick,

I actually found your example code, for changing the min and max size
of a UserControl on your site, and tried to adapt it, without success
(which is only a reflection on me, not your code :). I do not know the
type of struct necessary for LParam for this event (and was surprised
to not be able to same find easily on PInovke.Net or on [shudder,
gasp] MSDN).

One interesting thing : if the Form you are moving has no TitleBar (so
you are dragging it around with your own button or whatever) : I am
never seeing a WM_MOVING message, only WM_MOVE, in the Form's WndProc.
This seemed so "weird" that I double checked it.

Appended : the last WndProc messages of dragging a Form with no
TitleBar around.

best, Bill

form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600007
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xffffffffef010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xffffffffef010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600093
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xfffffffff2010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xfffffffff2010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x135 (WM_CTLCOLORBTN) hwnd=0x203b2 wparam=0x2d010b8e
lparam=0x503a4 result=0x0
form2 msg=0x2b (WM_DRAWITEM) hwnd=0x203b2 wparam=0x503a4
lparam=0x550d2ac result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x1c (WM_ACTIVATEAPP) hwnd=0x203b2 wparam=0x0 lparam=0xbbc
result=0x0
form2 msg=0x2 (WM_DESTROY) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
 
Mick Doherty wrote :
Intercept the WM_MOVING (0x216)  message and modify the RECT structure in
LParam before processing the message.

Thanks Mick,

I actually found your example code, for changing the min and max size
of a UserControl on your site, and tried to adapt it, without success
(which is only a reflection on me, not your code :). I do not know the
type of struct necessary for LParam for this event (and was surprised
to not be able to same find easily on PInovke.Net or on [shudder,
gasp] MSDN).

One interesting thing : if the Form you are moving has no TitleBar (so
you are dragging it around with your own button or whatever) : I am
never seeing a WM_MOVING message, only WM_MOVE, in the Form's WndProc.
This seemed so "weird" that I double checked it.

Appended : the last WndProc messages of dragging a Form with no
TitleBar around.

best, Bill

form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600007
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xffffffffef010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xffffffffef010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600093
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xfffffffff2010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xfffffffff2010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x135 (WM_CTLCOLORBTN) hwnd=0x203b2 wparam=0x2d010b8e
lparam=0x503a4 result=0x0
form2 msg=0x2b (WM_DRAWITEM) hwnd=0x203b2 wparam=0x503a4
lparam=0x550d2ac result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x1c (WM_ACTIVATEAPP) hwnd=0x203b2 wparam=0x0 lparam=0xbbc
result=0x0
form2 msg=0x2 (WM_DESTROY) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
 
Here's some code which adds a Moving Event to a form and uses that event to
prevent the form moving outside of the ClientRectangle of it's owner:

note: The form must have it's owner set before showing.
i.e. MainForm.AddOwnedForm(childForm);

--8<--------------------------------------------------

public event MovingEventHandler Moving;

public Form2()
{
InitializeComponent();

this.Moving += new MovingEventHandler(Form2_Moving);
}

void Form2_Moving(object sender, Form2.MovingEventArgs mev)
{
if (this.Owner != null)
{
Rectangle ClientBounds =
this.Owner.RectangleToScreen(this.Owner.ClientRectangle);
Size sz = new Size(mev.bounds.Width, mev.bounds.Height);
mev.bounds.X = Math.Min(Math.Max(mev.bounds.Left,
ClientBounds.Left), ClientBounds.Right - mev.bounds.Width);
mev.bounds.Y = Math.Min(Math.Max(mev.bounds.Top,
ClientBounds.Top), ClientBounds.Bottom - mev.bounds.Height);
mev.bounds.Width = sz.Width;
mev.bounds.Height = sz.Height;
}

}

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOVING)
{
RECT rc = ((RECT)m.GetLParam(typeof(RECT)));
MovingEventArgs mev = new MovingEventArgs(new Rectangle(rc.Left,
rc.Top, rc.Width, rc.Height));
OnMoving(mev);
rc.Left = mev.bounds.Left;
rc.Top = mev.bounds.Top;
rc.Right = mev.bounds.Right;
rc.Bottom = mev.bounds.Bottom;
Marshal.StructureToPtr(rc, m.LParam, true);
}
base.WndProc(ref m);
}

private void OnMoving(MovingEventArgs mev)
{
if (Moving != null)
this.Moving(this, mev);
}

public const int WM_MOVING = 0x216;

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left, Top, Right, Bottom;
public int Width
{
get { return this.Right - this.Left; }
}
public int Height
{
get { return this.Bottom - this.Top; }
}
public override string ToString()
{
return
String.Format(System.Globalization.CultureInfo.CurrentCulture,
"Left:{0}, Top:{1}, Width:{2}, Height:{3}", Left, Top,
Width, Height);
}
}

public class MovingEventArgs : EventArgs
{
public MovingEventArgs(Rectangle rectangle)
{
bounds = rectangle;
}

public Rectangle bounds;

}
public delegate void MovingEventHandler(object sender, MovingEventArgs
mev);

--8<--------------------------------------------------

This code also prevented the child form from moving outside of the owner
form when FormBorderStyle was set to None and the following method was used
to move the form:

--8<--------------------------------------------------

const int WM_NCLBUTTONDOWN = 0xA1;
const int HT_CAPTION = 0x2;

private void panel1_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
panel1.Capture = false;
Message msg = Message.Create(Handle, WM_NCLBUTTONDOWN,
(IntPtr)HT_CAPTION, IntPtr.Zero);
WndProc(ref msg);
}

--8<--------------------------------------------------

Regards,

Mick Doherty

uncleSally said:
Mick Doherty wrote :
Intercept the WM_MOVING (0x216) message and modify the RECT structure in
LParam before processing the message.

Thanks Mick,

I actually found your example code, for changing the min and max size
of a UserControl on your site, and tried to adapt it, without success
(which is only a reflection on me, not your code :). I do not know the
type of struct necessary for LParam for this event (and was surprised
to not be able to same find easily on PInovke.Net or on [shudder,
gasp] MSDN).

One interesting thing : if the Form you are moving has no TitleBar (so
you are dragging it around with your own button or whatever) : I am
never seeing a WM_MOVING message, only WM_MOVE, in the Form's WndProc.
This seemed so "weird" that I double checked it.

Appended : the last WndProc messages of dragging a Form with no
TitleBar around.

best, Bill

form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600007
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xffffffffef010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xffffffffef010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600093
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xfffffffff2010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xfffffffff2010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x135 (WM_CTLCOLORBTN) hwnd=0x203b2 wparam=0x2d010b8e
lparam=0x503a4 result=0x0
form2 msg=0x2b (WM_DRAWITEM) hwnd=0x203b2 wparam=0x503a4
lparam=0x550d2ac result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x1c (WM_ACTIVATEAPP) hwnd=0x203b2 wparam=0x0 lparam=0xbbc
result=0x0
form2 msg=0x2 (WM_DESTROY) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
 
Here's some code which adds a Moving Event to a form and uses that event to
prevent the form moving outside of the ClientRectangle of it's owner:

note: The form must have it's owner set before showing.
i.e. MainForm.AddOwnedForm(childForm);

--8<--------------------------------------------------

public event MovingEventHandler Moving;

public Form2()
{
InitializeComponent();

this.Moving += new MovingEventHandler(Form2_Moving);
}

void Form2_Moving(object sender, Form2.MovingEventArgs mev)
{
if (this.Owner != null)
{
Rectangle ClientBounds =
this.Owner.RectangleToScreen(this.Owner.ClientRectangle);
Size sz = new Size(mev.bounds.Width, mev.bounds.Height);
mev.bounds.X = Math.Min(Math.Max(mev.bounds.Left,
ClientBounds.Left), ClientBounds.Right - mev.bounds.Width);
mev.bounds.Y = Math.Min(Math.Max(mev.bounds.Top,
ClientBounds.Top), ClientBounds.Bottom - mev.bounds.Height);
mev.bounds.Width = sz.Width;
mev.bounds.Height = sz.Height;
}

}

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MOVING)
{
RECT rc = ((RECT)m.GetLParam(typeof(RECT)));
MovingEventArgs mev = new MovingEventArgs(new Rectangle(rc.Left,
rc.Top, rc.Width, rc.Height));
OnMoving(mev);
rc.Left = mev.bounds.Left;
rc.Top = mev.bounds.Top;
rc.Right = mev.bounds.Right;
rc.Bottom = mev.bounds.Bottom;
Marshal.StructureToPtr(rc, m.LParam, true);
}
base.WndProc(ref m);
}

private void OnMoving(MovingEventArgs mev)
{
if (Moving != null)
this.Moving(this, mev);
}

public const int WM_MOVING = 0x216;

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left, Top, Right, Bottom;
public int Width
{
get { return this.Right - this.Left; }
}
public int Height
{
get { return this.Bottom - this.Top; }
}
public override string ToString()
{
return
String.Format(System.Globalization.CultureInfo.CurrentCulture,
"Left:{0}, Top:{1}, Width:{2}, Height:{3}", Left, Top,
Width, Height);
}
}

public class MovingEventArgs : EventArgs
{
public MovingEventArgs(Rectangle rectangle)
{
bounds = rectangle;
}

public Rectangle bounds;

}
public delegate void MovingEventHandler(object sender, MovingEventArgs
mev);

--8<--------------------------------------------------

This code also prevented the child form from moving outside of the owner
form when FormBorderStyle was set to None and the following method was used
to move the form:

--8<--------------------------------------------------

const int WM_NCLBUTTONDOWN = 0xA1;
const int HT_CAPTION = 0x2;

private void panel1_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
panel1.Capture = false;
Message msg = Message.Create(Handle, WM_NCLBUTTONDOWN,
(IntPtr)HT_CAPTION, IntPtr.Zero);
WndProc(ref msg);
}

--8<--------------------------------------------------

Regards,

Mick Doherty

uncleSally said:
Mick Doherty wrote :
Intercept the WM_MOVING (0x216) message and modify the RECT structure in
LParam before processing the message.

Thanks Mick,

I actually found your example code, for changing the min and max size
of a UserControl on your site, and tried to adapt it, without success
(which is only a reflection on me, not your code :). I do not know the
type of struct necessary for LParam for this event (and was surprised
to not be able to same find easily on PInovke.Net or on [shudder,
gasp] MSDN).

One interesting thing : if the Form you are moving has no TitleBar (so
you are dragging it around with your own button or whatever) : I am
never seeing a WM_MOVING message, only WM_MOVE, in the Form's WndProc.
This seemed so "weird" that I double checked it.

Appended : the last WndProc messages of dragging a Form with no
TitleBar around.

best, Bill

form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e3d0 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600007
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xffffffffef010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xffffffffef010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550d708
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e300 result=0x0
form2 msg=0x3 (WM_MOVE) hwnd=0x203b2 wparam=0x0 lparam=0x1600093
result=0x0
form2 msg=0x14 (WM_ERASEBKGND) hwnd=0x203b2 wparam=0xfffffffff2010e83
lparam=0x0 result=0x0
form2 msg=0x318 (WM_PRINTCLIENT) hwnd=0x203b2
wparam=0xfffffffff2010e83 lparam=0x4 result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0xe (WM_GETTEXTLENGTH) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0xd (WM_GETTEXT) hwnd=0x203b2 wparam=0x1 lparam=0x550dc94
result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x7039a
result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550dd1c result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x1 lparam=0x7039a
result=0x0
form2 msg=0x135 (WM_CTLCOLORBTN) hwnd=0x203b2 wparam=0x2d010b8e
lparam=0x503a4 result=0x0
form2 msg=0x2b (WM_DRAWITEM) hwnd=0x203b2 wparam=0x503a4
lparam=0x550d2ac result=0x0
form2 msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x203b2 wparam=0x0
lparam=0x550e8dc result=0x0
form2 msg=0x86 (WM_NCACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x6 (WM_ACTIVATE) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
form2 msg=0x1c (WM_ACTIVATEAPP) hwnd=0x203b2 wparam=0x0 lparam=0xbbc
result=0x0
form2 msg=0x2 (WM_DESTROY) hwnd=0x203b2 wparam=0x0 lparam=0x0
result=0x0
 
Mick said:
Here's some code which adds a Moving Event to a form and uses that event to
prevent the form moving outside of the ClientRectangle of it's owner:

note: The form must have it's owner set before showing.
i.e. MainForm.AddOwnedForm(childForm);

Hi Mick,

Thanks very much for sending that code : I guarantee you I will study
it very carefully !

Just a reminder that, as I said in a previous message, I am dealing
here with the case of moving Forms (which I'm calling "secondary
forms") over a another form (which I am calling "the master form")
which are indepedent : i.e., they do not have a Parent set, they are
not child forms.

Why am I doing this : simple : then each secondary Form can have an
independent opacity setting or transparency key.

I've actually got some code working now that is doing a better-than-
expected job (visually) of keeping these independent secondary forms
in the bounds of the "master form" and moving them when the master
form is move.

But I will experiment with your code, and look forward to that :)

thanks, Bill
 
Mick said:
Here's some code which adds a Moving Event to a form and uses that event to
prevent the form moving outside of the ClientRectangle of it's owner:

note: The form must have it's owner set before showing.
i.e. MainForm.AddOwnedForm(childForm);

Hi Mick,

Thanks very much for sending that code : I guarantee you I will study
it very carefully !

Just a reminder that, as I said in a previous message, I am dealing
here with the case of moving Forms (which I'm calling "secondary
forms") over a another form (which I am calling "the master form")
which are indepedent : i.e., they do not have a Parent set, they are
not child forms.

Why am I doing this : simple : then each secondary Form can have an
independent opacity setting or transparency key.

I've actually got some code working now that is doing a better-than-
expected job (visually) of keeping these independent secondary forms
in the bounds of the "master form" and moving them when the master
form is move.

But I will experiment with your code, and look forward to that :)

thanks, Bill
 
Hi Bill,

Although I called it childForm, it has no parent set and so Opacity or
TransparencyKey can be set independently.
It only has an owner so that we can easily refer to the ClientRectangle of
the Master Form, but that is not a necessity.

You'll still need to move the secondary form as the master form moves as I
have made no allowance for that, but that could easily use the same method.

Create a form with the Moving event and Inherit from that instead of
'System.Windows.Forms.Form'. You can then place whatever code is necessary
in the Moving event without upsetting any of your existing code or layout.

Regards,

Mick Doherty
http://dotnetrix.co.uk/form.htm
 
Back
Top