我想,你所需要的 - 弹出位置校正。您可以定义自定义行为。我解决了类似的问题,想和你分享我的代码。我相信你可以改变它以获得必要的行为。
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;
namespace YourNameSpace
{
public class PopupExtendedPlacementBehavior : Behavior<Popup>
{
private static DependencyPropertyDescriptor PopupChildDescriptor
= DependencyPropertyDescriptor.FromProperty(Popup.ChildProperty, typeof(Popup));
private static FrameworkPropertyMetadata PlacementMetadata
= new FrameworkPropertyMetadata(ExtendedPlacementMode.Default);
public static DependencyProperty PlacementProperty
= DependencyProperty.Register("Placement", typeof(ExtendedPlacementMode), typeof(PopupExtendedPlacementBehavior), PlacementMetadata);
private static FrameworkPropertyMetadata IndentFromTargetMetadata
= new FrameworkPropertyMetadata(0.0);
public static DependencyProperty IndentFromTargetProperty
= DependencyProperty.Register("IndentFromTarget", typeof(double), typeof(PopupExtendedPlacementBehavior), IndentFromTargetMetadata);
public ExtendedPlacementMode Placement
{
get => (ExtendedPlacementMode)GetValue(PlacementProperty);
set => SetValue(PlacementProperty, value);
}
public double IndentFromTarget
{
get => (double)GetValue(IndentFromTargetProperty);
set => SetValue(IndentFromTargetProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Opened += OnChangePlacement;
AssociatedObject.SizeChanged += OnChangePlacement;
PopupChildDescriptor.AddValueChanged(AssociatedObject, OnChangePlacement);
}
protected override void OnDetaching()
{
AssociatedObject.Opened -= OnChangePlacement;
AssociatedObject.SizeChanged -= OnChangePlacement;
PopupChildDescriptor.RemoveValueChanged(AssociatedObject, OnChangePlacement);
base.OnDetaching();
}
private void OnChangePlacement(object sender, EventArgs e)
{
if (CanSetPlacement())
{
SetPlacement(Placement);
}
}
private bool CanSetPlacement()
{
return
AssociatedObject.Placement == PlacementMode.Bottom
||
AssociatedObject.Placement == PlacementMode.Top
||
AssociatedObject.Placement == PlacementMode.Right
||
AssociatedObject.Placement == PlacementMode.Left;
}
private void SetPlacement(ExtendedPlacementMode mode)
{
var offset = new Point();
switch (mode)
{
case ExtendedPlacementMode.Default:
return;
case ExtendedPlacementMode.Left | ExtendedPlacementMode.Top:
AssociatedObject.Placement = PlacementMode.Left;
offset = GetOffset(AssociatedObject, GetTopOffset);
offset.X -= IndentFromTarget;
offset.Y -= IndentFromTarget;
break;
case ExtendedPlacementMode.Left | ExtendedPlacementMode.Bottom:
AssociatedObject.Placement = PlacementMode.Left;
offset = GetOffset(AssociatedObject, GetBottomOffset);
offset.X -= IndentFromTarget;
offset.Y += IndentFromTarget;
break;
case ExtendedPlacementMode.Right | ExtendedPlacementMode.Top:
AssociatedObject.Placement = PlacementMode.Right;
offset = GetOffset(AssociatedObject, GetTopOffset);
offset.X += IndentFromTarget;
offset.Y -= IndentFromTarget;
break;
case ExtendedPlacementMode.Right | ExtendedPlacementMode.Bottom:
AssociatedObject.Placement = PlacementMode.Right;
offset = GetOffset(AssociatedObject, GetBottomOffset);
offset.X += IndentFromTarget;
offset.Y += IndentFromTarget;
break;
case ExtendedPlacementMode.Left:
AssociatedObject.Placement = PlacementMode.Left;
offset = GetOffset(AssociatedObject, GetHorizontalCenterOffset);
offset.X -= IndentFromTarget;
break;
case ExtendedPlacementMode.Right:
AssociatedObject.Placement = PlacementMode.Right;
offset = GetOffset(AssociatedObject, GetHorizontalCenterOffset);
offset.X += IndentFromTarget;
break;
case ExtendedPlacementMode.Center:
AssociatedObject.Placement = PlacementMode.Center;
break;
case ExtendedPlacementMode.Top:
AssociatedObject.Placement = PlacementMode.Top;
offset = GetOffset(AssociatedObject, GetVerticalCenterOffset);
offset.Y -= IndentFromTarget;
break;
case ExtendedPlacementMode.Bottom:
AssociatedObject.Placement = PlacementMode.Bottom;
offset = GetOffset(AssociatedObject, GetVerticalCenterOffset);
offset.Y += IndentFromTarget;
break;
}
AssociatedObject.HorizontalOffset = offset.X;
AssociatedObject.VerticalOffset = offset.Y;
}
private static Point GetOffset(Popup popup, Func<FrameworkElement, FrameworkElement, Point> getOffset)
{
var target = popup.PlacementTarget as FrameworkElement;
var child = (popup.Child ?? popup) as FrameworkElement;
if (target != null && child != null)
{
return getOffset(target, child);
}
return new Point();
}
private static Point GetHorizontalCenterOffset(FrameworkElement target, FrameworkElement popup)
{
var y = (target.ActualHeight - popup.ActualHeight) / 2;
return new Point(0.0, y);
}
private static Point GetVerticalCenterOffset(FrameworkElement target, FrameworkElement popup)
{
var x = (target.ActualWidth - popup.ActualWidth) / 2;
return new Point(x, 0.0);
}
private static Point GetTopOffset(FrameworkElement target, FrameworkElement popup)
{
var y = -popup.ActualHeight;
return new Point(0.0, y);
}
private static Point GetBottomOffset(FrameworkElement target, FrameworkElement popup)
{
var y = target.ActualHeight;
return new Point(0.0, y);
}
}
[Flags]
public enum ExtendedPlacementMode
{
Default = 0,
Left = 1,
Right = 2,
Top = 4,
Bottom = 8,
Center = 16
}
}
<UserControl
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:beh="clr-namespace:YourNameSpace;assembly=YourAssembly">
<Popup>
<i:Interaction.Behaviors>
<beh:PopupExtendedPlacementBehavior Placement="Bottom,Right" IndentFromTarget="4"/>
</i:Interaction.Behaviors>
</Popup>
</UserControl>