优化更新代码,添加界面功能并整合
This commit is contained in:
231
WPFluent/Controls/Primitives/CustomPopupPlacementHelper.cs
Normal file
231
WPFluent/Controls/Primitives/CustomPopupPlacementHelper.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace WPFluent.Controls.Primitives;
|
||||
|
||||
internal static class CustomPopupPlacementHelper
|
||||
{
|
||||
public static readonly DependencyProperty PlacementProperty =
|
||||
DependencyProperty.RegisterAttached("Placement", typeof(CustomPlacementMode), typeof(CustomPopupPlacementHelper), new PropertyMetadata(CustomPlacementMode.Top));
|
||||
|
||||
public static CustomPlacementMode GetPlacement(DependencyObject element)
|
||||
{
|
||||
return (CustomPlacementMode)element.GetValue(PlacementProperty);
|
||||
}
|
||||
|
||||
public static void SetPlacement(DependencyObject element, CustomPlacementMode value)
|
||||
{
|
||||
element.SetValue(PlacementProperty, value);
|
||||
}
|
||||
|
||||
internal static CustomPopupPlacement[] PositionPopup(
|
||||
CustomPlacementMode placement,
|
||||
Size popupSize,
|
||||
Size targetSize,
|
||||
Point offset,
|
||||
FrameworkElement child = null!)
|
||||
{
|
||||
Matrix transformToDevice = default;
|
||||
if (child != null)
|
||||
{
|
||||
Helper.TryGetTransformToDevice(child, out transformToDevice);
|
||||
}
|
||||
|
||||
var preferredPlacement = CalculatePopupPlacement(placement, popupSize, targetSize, offset, child!, transformToDevice);
|
||||
|
||||
CustomPopupPlacement? alternativePlacement = null;
|
||||
var alternativePlacementMode = GetAlternativePlacementMode(placement);
|
||||
if (alternativePlacementMode.HasValue)
|
||||
{
|
||||
alternativePlacement = CalculatePopupPlacement(alternativePlacementMode.Value, popupSize, targetSize, offset, child!, transformToDevice);
|
||||
}
|
||||
|
||||
if (alternativePlacement.HasValue)
|
||||
{
|
||||
return [preferredPlacement, alternativePlacement.Value];
|
||||
}
|
||||
else
|
||||
{
|
||||
return [preferredPlacement];
|
||||
}
|
||||
}
|
||||
|
||||
private static CustomPopupPlacement CalculatePopupPlacement(
|
||||
CustomPlacementMode placement,
|
||||
Size popupSize,
|
||||
Size targetSize,
|
||||
Point offset,
|
||||
FrameworkElement child = null!,
|
||||
Matrix transformToDevice = default)
|
||||
{
|
||||
Point point;
|
||||
PopupPrimaryAxis primaryAxis;
|
||||
|
||||
switch (placement)
|
||||
{
|
||||
case CustomPlacementMode.Top:
|
||||
point = new Point((targetSize.Width - popupSize.Width) / 2, -popupSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.Bottom:
|
||||
point = new Point((targetSize.Width - popupSize.Width) / 2, targetSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.Left:
|
||||
point = new Point(-popupSize.Width, (targetSize.Height - popupSize.Height) / 2);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.Right:
|
||||
point = new Point(targetSize.Width, (targetSize.Height - popupSize.Height) / 2);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.Full:
|
||||
point = new Point((targetSize.Width - popupSize.Width) / 2, (targetSize.Height - popupSize.Height) / 2);
|
||||
primaryAxis = PopupPrimaryAxis.None;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.TopEdgeAlignedLeft:
|
||||
point = new Point(0, -popupSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.TopEdgeAlignedRight:
|
||||
point = new Point(targetSize.Width - popupSize.Width, -popupSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.BottomEdgeAlignedLeft:
|
||||
point = new Point(0, targetSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.BottomEdgeAlignedRight:
|
||||
point = new Point(targetSize.Width - popupSize.Width, targetSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Horizontal;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.LeftEdgeAlignedTop:
|
||||
point = new Point(-popupSize.Width, 0);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.LeftEdgeAlignedBottom:
|
||||
point = new Point(-popupSize.Width, targetSize.Height - popupSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.RightEdgeAlignedTop:
|
||||
point = new Point(targetSize.Width, 0);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
|
||||
case CustomPlacementMode.RightEdgeAlignedBottom:
|
||||
point = new Point(targetSize.Width, targetSize.Height - popupSize.Height);
|
||||
primaryAxis = PopupPrimaryAxis.Vertical;
|
||||
break;
|
||||
//case CustomPopupPlacementMode.Auto:
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(placement));
|
||||
}
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
var childOffset = VisualTreeHelper.GetOffset(child);
|
||||
if (transformToDevice != default)
|
||||
{
|
||||
childOffset = transformToDevice.Transform(childOffset);
|
||||
}
|
||||
point -= childOffset;
|
||||
}
|
||||
|
||||
return new CustomPopupPlacement(point, primaryAxis);
|
||||
}
|
||||
|
||||
private static CustomPlacementMode? GetAlternativePlacementMode(CustomPlacementMode placement)
|
||||
{
|
||||
switch (placement)
|
||||
{
|
||||
case CustomPlacementMode.Top:
|
||||
return CustomPlacementMode.Bottom;
|
||||
|
||||
case CustomPlacementMode.Bottom:
|
||||
return CustomPlacementMode.Top;
|
||||
|
||||
case CustomPlacementMode.Left:
|
||||
return CustomPlacementMode.Right;
|
||||
|
||||
case CustomPlacementMode.Right:
|
||||
return CustomPlacementMode.Left;
|
||||
|
||||
case CustomPlacementMode.Full:
|
||||
return null;
|
||||
|
||||
case CustomPlacementMode.TopEdgeAlignedLeft:
|
||||
return CustomPlacementMode.BottomEdgeAlignedLeft;
|
||||
|
||||
case CustomPlacementMode.TopEdgeAlignedRight:
|
||||
return CustomPlacementMode.BottomEdgeAlignedRight;
|
||||
|
||||
case CustomPlacementMode.BottomEdgeAlignedLeft:
|
||||
return CustomPlacementMode.TopEdgeAlignedLeft;
|
||||
|
||||
case CustomPlacementMode.BottomEdgeAlignedRight:
|
||||
return CustomPlacementMode.TopEdgeAlignedRight;
|
||||
|
||||
case CustomPlacementMode.LeftEdgeAlignedTop:
|
||||
return CustomPlacementMode.RightEdgeAlignedTop;
|
||||
|
||||
case CustomPlacementMode.LeftEdgeAlignedBottom:
|
||||
return CustomPlacementMode.RightEdgeAlignedBottom;
|
||||
|
||||
case CustomPlacementMode.RightEdgeAlignedTop:
|
||||
return CustomPlacementMode.RightEdgeAlignedTop;
|
||||
|
||||
case CustomPlacementMode.RightEdgeAlignedBottom:
|
||||
return CustomPlacementMode.LeftEdgeAlignedBottom;
|
||||
//case CustomPopupPlacementMode.Auto:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum CustomPlacementMode
|
||||
{
|
||||
Top = 0,
|
||||
Bottom = 1,
|
||||
Left = 2,
|
||||
Right = 3,
|
||||
Full = 4,
|
||||
TopEdgeAlignedLeft = 5,
|
||||
TopEdgeAlignedRight = 6,
|
||||
BottomEdgeAlignedLeft = 7,
|
||||
BottomEdgeAlignedRight = 8,
|
||||
LeftEdgeAlignedTop = 9,
|
||||
LeftEdgeAlignedBottom = 10,
|
||||
RightEdgeAlignedTop = 11,
|
||||
RightEdgeAlignedBottom = 12,
|
||||
//Auto = 13
|
||||
}
|
||||
|
||||
file static class Helper
|
||||
{
|
||||
public static bool TryGetTransformToDevice(Visual visual, out Matrix value)
|
||||
{
|
||||
var presentationSource = PresentationSource.FromVisual(visual);
|
||||
if (presentationSource != null)
|
||||
{
|
||||
value = presentationSource.CompositionTarget.TransformToDevice;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user