如何修改MouseDragPopupBehavior以限制Popup拖拽范围在应用窗口内
限制Popup拖拽范围到指定父容器的实现方案
修改思路
现有代码仅实现了基础拖拽功能,我们通过以下调整增加范围限制:
- 新增
ParentContainer依赖属性,支持绑定你要限制的父容器(比如应用主窗口) - 拖拽计算偏移后,先获取父容器和Popup的屏幕坐标、实际尺寸,做边界校验
- 仅允许Popup的所有边缘都在父容器范围内,超出时自动校正偏移量
修改后完整代码
public class MouseDragPopupBehavior : Behavior<Popup> { private bool mouseDown; private Point oldMousePosition; // 可绑定的父容器属性,指定拖拽限制的边界容器 public static readonly DependencyProperty ParentContainerProperty = DependencyProperty.Register(nameof(ParentContainer), typeof(UIElement), typeof(MouseDragPopupBehavior), new PropertyMetadata(null)); public UIElement ParentContainer { get => (UIElement)GetValue(ParentContainerProperty); set => SetValue(ParentContainerProperty, value); } protected override void OnAttached() { AssociatedObject.MouseLeftButtonDown += (s, e) => { mouseDown = true; oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject)); AssociatedObject.Child.CaptureMouse(); }; AssociatedObject.MouseMove += (s, e) => { if (!mouseDown || ParentContainer == null) return; var newMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject)); var offset = newMousePosition - oldMousePosition; oldMousePosition = newMousePosition; // 计算边界参数 var popupCurrentLeft = AssociatedObject.PointToScreen(new Point(0, 0)).X; var popupCurrentTop = AssociatedObject.PointToScreen(new Point(0, 0)).Y; var popupWidth = AssociatedObject.ActualWidth; var popupHeight = AssociatedObject.ActualHeight; var parentLeft = ParentContainer.PointToScreen(new Point(0, 0)).X; var parentTop = ParentContainer.PointToScreen(new Point(0, 0)).Y; var parentRight = parentLeft + ParentContainer.RenderSize.Width; var parentBottom = parentTop + ParentContainer.RenderSize.Height; // 校正水平偏移 var expectedLeft = popupCurrentLeft + offset.X; var expectedRight = expectedLeft + popupWidth; if (expectedLeft < parentLeft) { offset.X = parentLeft - popupCurrentLeft; } else if (expectedRight > parentRight) { offset.X = parentRight - popupCurrentLeft - popupWidth; } // 校正垂直偏移 var expectedTop = popupCurrentTop + offset.Y; var expectedBottom = expectedTop + popupHeight; if (expectedTop < parentTop) { offset.Y = parentTop - popupCurrentTop; } else if (expectedBottom > parentBottom) { offset.Y = parentBottom - popupCurrentTop - popupHeight; } // 应用校正后的偏移 AssociatedObject.HorizontalOffset += offset.X; AssociatedObject.VerticalOffset += offset.Y; }; AssociatedObject.MouseLeftButtonUp += (s, e) => { mouseDown = false; AssociatedObject.Child.ReleaseMouseCapture(); }; } }
使用方式
在XAML中给Behavior绑定父容器即可,比如要限制在当前窗口内,写法如下:
<Popup> <i:Interaction.Behaviors> <local:MouseDragPopupBehavior ParentContainer="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" /> </i:Interaction.Behaviors> <!-- Popup内容 --> </Popup>
如果要限制在其他容器比如Grid里,只需要把AncestorType改成对应容器类型即可。
内容的提问来源于stack exchange,提问作者Julien
相关产品推荐
相关产品推荐

