我有一个应用程序,我在WPF中创建一个用户可以拖动的窗口。我想限制它,以便它不会超过父窗口的主菜单。如果我处理 WindowLocationChanged 事件,那么在后触发已经发生了更改,所以我唯一能做的就是强制窗口回到其他位置,这会产生不良的视觉效果的效果。
是否有任何事件我可以处理之前实际发生了移动因此我可以触发窗口并强制它保持在一定限度内?一些商业WPF库支持 OnMoving 事件,该事件在移动实际发生在屏幕上之前被触发。在本机WPF中是否存在类似内容(如果可能,保留在托管代码环境中)?
或者,有没有办法使用依赖属性来设置max或min x,y值? (N.B.,我正在移动它,而不是调整它)
提前致谢。
答案 0 :(得分:7)
这个例子是一个演示,展示如何防止Window移动到它的开始X / Y位置......它应该为你提供你想要做的起点。
注意,调整大小以改变顶部和左侧位置是可能的,这也是为什么要处理WM_SIZING消息以确保调整大小不会这样做。
如果您不需要,那么只需取出WM_SIZING案例。
<Window x:Class="WpfApplication12.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace WpfApplication12
{
[StructLayout(LayoutKind.Sequential)]
public struct WIN32Rectangle
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
const int WM_SIZING = 0x0214;
const int WM_MOVING = 0x0216;
private Point InitialWindowLocation;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
HwndSource.FromHwnd(helper.Handle).AddHook(HwndMessageHook);
InitialWindowLocation = new Point(this.Left, this.Top);
}
private IntPtr HwndMessageHook(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref bool bHandled)
{
switch (msg)
{
// You may prefer to check the specific size action being done
//
//case WM_SIZING:
// {
// case (wParam)
// {
// case WMSZ_LEFT:
// {
// }
// break;
// case WSSZ_TOP:
// {
// }
// break;
// case WSSZ_TOPLEFT:
// {
// }
// break;
// }
// }
// break;
case WM_SIZING:
case WM_MOVING:
{
WIN32Rectangle rectangle = (WIN32Rectangle)Marshal.PtrToStructure(lParam, typeof(WIN32Rectangle));
if (rectangle.Left < this.InitialWindowLocation.X)
{
rectangle.Left = (int)this.InitialWindowLocation.X;
rectangle.Right = (int)this.Left + (int)this.Width;
bHandled = true;
}
if (rectangle.Top < this.InitialWindowLocation.Y)
{
rectangle.Top = (int)this.InitialWindowLocation.Y;
rectangle.Bottom = (int)this.Top + (int)this.Height;
bHandled = true;
}
if (bHandled)
{
Marshal.StructureToPtr(rectangle, lParam, true);
}
}
break;
}
return IntPtr.Zero;
}
}
}