有两种方法可以做到这一点。
Using 地点已结束 http://msdn.microsoft.com/en-us/library/system.windows.window.locationchanged.aspx
如果处理此事件,您可以将顶部或左侧更改为在所有者窗口的范围内。
例如
private void Window_LocationChanged(object sender, EventArgs e)
{
if (this.Left < this.Owner.Left)
this.Left = this.Owner.Left;
//... also right top and bottom
//
}
这很容易写,但它违反了最小惊讶原则 http://en.wikipedia.org/wiki/Principle_of_least_surprise因为它没有绑定拖动窗口,所以当用户放开鼠标按钮时,它只是将窗口推回原位。
Using AddHook http://msdn.microsoft.com/en-us/library/system.windows.interop.hwndsource.addhook.aspxhttp://msdn.microsoft.com/en-us/library/system.windows.interop.hwndsource.addhook.aspx
正如彼得在书中指出的那样一个答案 https://stackoverflow.com/questions/3967432/c-wpf-dragmove-without-window-locationchanged/3970282#3970282对于类似的问题,您可以 Interop 到 Windows 消息传递并阻止拖动窗口。这有很好的效果限制实际的拖动窗口.
这是我为 AddHook 方法整理的一些示例代码
从加载的窗口开始添加钩子
//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);
}
在您的处理程序中,您只想查找移动或移动消息。然后您将读取 lParam 矩形并查看它是否超出范围。如果是,您需要更改 lParam 矩形的值并将其封送回来。请注意,为了简洁起见,我只做了左侧。您仍然需要写出右侧、顶部和底部的情况。
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;
}
lParam 的结构
[StructLayout(LayoutKind.Sequential)]
//Struct for Marshalling the lParam
public struct MoveRectangle
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
最后一点,您需要弄清楚如果允许子窗口大于父窗口,该怎么办。