Make a window draggable within a certain boundary WPF
I have a wpf child window that I allow dragging by using the DragMove() me开发者_开发百科thod. However, I need to allow the window to be dragged only within the bounds of its Parent window control.
Can anyone suggest a way to achieve this? Thanks!
There are two ways to do this.
Using LocationEnded
If you handle this event you can change the Top or Left to be within the bounds of the owner window. e.g.
private void Window_LocationChanged(object sender, EventArgs e)
{
if (this.Left < this.Owner.Left)
this.Left = this.Owner.Left;
//... also right top and bottom
//
}
This is fairly easy to write, but it violates the Principle of least astonishment as it doesn't bound the drag window it just pushes the window back to place when the user lets go of the mouse button.
Using AddHook
As Pieter points out in an answer to a similar question you can Interop to the Windows messaging and block the drag window. This has the nice affect of bounding the actual drag window.
Here's some sample code I put together for the AddHook approach
Start with the window loaded to add the hook
//In Window_Loaded the handle is there (earlier its null) so this is good time to add the handler
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
HwndSource.FromHwnd(helper.Handle).AddHook(HwndSourceHookHandler);
}
In your handler you want to only look for moving or move message. Then you'll read the lParam rectangle and see if it out of bounds. If it is you'll need to change the values of the lParam rectangle and Marshal it back. Note for brevity's sake I only did the left. You'll still need to write out the right, top and bottom cases.
private IntPtr HwndSourceHookHandler(IntPtr hwnd, int msg, IntPtr wParam,
IntPtr lParam, ref bool handled)
{
const int WM_MOVING = 0x0216;
const int WM_MOVE = 0x0003;
switch (msg)
{
case WM_MOVING:
{
//read the lparm ino a struct
MoveRectangle rectangle = (MoveRectangle)Marshal.PtrToStructure(
lParam, typeof(MoveRectangle));
//
if (rectangle.Left < this.Owner.Left)
{
rectangle.Left = (int)this.Owner.Left;
rectangle.Right = rectangle.Left + (int)this.Width;
}
Marshal.StructureToPtr(rectangle, lParam, true);
break;
}
case WM_MOVE:
{
//Do the same thing as WM_MOVING You should probably enacapsulate that stuff so don'tn just copy and paste
break;
}
}
return IntPtr.Zero;
}
the struct for the lParam
[StructLayout(LayoutKind.Sequential)]
//Struct for Marshalling the lParam
public struct MoveRectangle
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
One final note you'll need to figure out what to do if you Child window is allowed to be bigger than the parent window.
精彩评论