重新规划拖放装饰器绘制逻辑

This commit is contained in:
zengwenjie
2025-09-26 14:40:02 +08:00
parent c65972b1a9
commit ba725b7bfe
11 changed files with 50 additions and 72 deletions

View File

@@ -748,6 +748,7 @@ namespace Deedy.Activity
protected internal DropPlacement _DropPlacement = DropPlacement.Uncertain;
protected override void OnDragOver(DragEventArgs e)
{
//HACK这里要考虑父容器的布局方向
if (this.IsEventNeedToHandle(e.OriginalSource))
{
this.RefreshViewerState(true);
@@ -759,17 +760,17 @@ namespace Deedy.Activity
if (this._CanDropInParent && (currentPoint.Y < 10 || currentPoint.Y < 10))
{
this._DropPlacement = DropPlacement.BeforeMe;
this.UpdateDragAdorner(Dock.Top);
this.UpdateDragAdorner(this._DropPlacement);
}
else if (this._CanDropInParent && (hitElement.ActualHeight - currentPoint.Y < 10 || hitElement.ActualWidth - currentPoint.X < 10))
{
this._DropPlacement = DropPlacement.BehindMe;
this.UpdateDragAdorner(Dock.Bottom);
this.UpdateDragAdorner(this._DropPlacement);
}
else if (this._CanDropChild)
{
this._DropPlacement = DropPlacement.WithinMe;
this.UpdateDragAdorner(null);
this.UpdateDragAdorner(this._DropPlacement);
}
else
{

View File

@@ -7,65 +7,34 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using Deedy.Activity.Helpers;
namespace Deedy.Activity
{
public class DragPlacementAdorner : Adorner
{
private static readonly Pen _PrevPen;
private static readonly Pen _NextPen;
private static readonly Pen _PartPen;
public Dock? Position { get; private set; }
private static readonly Pen _Pen;
private static readonly Brush _Brush;
public DropPlacement DropPlacement { get; private set; }
public LayoutDirection? LayoutDirection { get; private set; }
static DragPlacementAdorner()
{
// 定义装饰器的画笔
_PrevPen = new Pen(Brushes.Red, 5.0);
_PrevPen.Freeze();
_NextPen = new Pen(Brushes.Red, 5.0);
_NextPen.Freeze();
_PartPen = new Pen(Brushes.Blue, 3.0);
_PartPen.Freeze();
// 定义装饰器的画笔与画刷
_Pen = new Pen(Brushes.Transparent, 0);
_Pen.Freeze();
_Brush = new SolidColorBrush(Colors.Red) { Opacity = 0.5 };
_Brush.Freeze();
}
public DragPlacementAdorner(UIElement adornedElement, Dock? dock) : base(adornedElement)
public DragPlacementAdorner(UIElement adornedElement, DropPlacement dropPlacement, LayoutDirection? parentLayoutDirection) : base(adornedElement)
{
this.Position = dock;
this.DropPlacement = dropPlacement;
this.LayoutDirection = parentLayoutDirection;
IsHitTestVisible = false;
}
protected override void OnRender(DrawingContext drawingContext)
{
var adornedElementRect = new Rect(AdornedElement.RenderSize);
// 根据位置信息绘制不同的视觉效果
switch (this.Position)
{
case Dock.Top:
drawingContext.DrawLine(_PrevPen,
new Point(0, 0),
new Point(adornedElementRect.Right, 0));
break;
case Dock.Bottom:
drawingContext.DrawLine(_NextPen,
new Point(0, adornedElementRect.Bottom),
new Point(adornedElementRect.Right, adornedElementRect.Bottom));
break;
case Dock.Left:
drawingContext.DrawLine(_PrevPen,
new Point(0, 0),
new Point(0, adornedElementRect.Bottom));
break;
case Dock.Right:
drawingContext.DrawLine(_NextPen,
new Point(adornedElementRect.Right, 0),
new Point(adornedElementRect.Right, adornedElementRect.Bottom));
break;
case null:
drawingContext.DrawRectangle(null, _PartPen, adornedElementRect);
break;
default: break;
}
}
=> this.Help_DrawDropAdorner(drawingContext, this.DropPlacement, this.LayoutDirection, _Pen, _Brush);
}
}

View File

@@ -13,5 +13,6 @@ namespace Deedy.Activity
public interface ICombinedElement : IElement
{
public ElementCollection Elements { get; set; }
public LayoutDirection Direction { get; set; }
}
}

View File

@@ -11,5 +11,6 @@ namespace Deedy.Activity
public CombinedLogical() { }
public ElementCollection Elements { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public LayoutDirection Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
}

View File

@@ -12,6 +12,7 @@ namespace Deedy.Activity
public ContainerLogical() { }
public abstract ElementCollection Elements { get; set; }
public LayoutDirection Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public abstract void Append(IElement element);
public abstract bool CombineChecking(IElement element, out DragDropEffects effects);

View File

@@ -11,5 +11,6 @@ namespace Deedy.Activity
public CombinedFunction() { }
public ElementCollection Elements { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public LayoutDirection Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
}

View File

@@ -12,6 +12,7 @@ namespace Deedy.Activity
public ContainerFunction() { }
public abstract ElementCollection Elements { get; set; }
public LayoutDirection Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public abstract void Append(IElement element);
public abstract bool CombineChecking(IElement element, out DragDropEffects effects);

View File

@@ -8,6 +8,5 @@ namespace Deedy.Activity
{
public interface IVisualLayout : IContainerElement
{
LayoutDirection LayoutDirection { get; }
}
}

View File

@@ -36,6 +36,8 @@ namespace Deedy.Activity
public LayoutDirection LayoutDirection => throw new NotImplementedException();
public LayoutDirection Direction { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>

View File

@@ -40,8 +40,9 @@ namespace Deedy.Activity
/// 更新一个「UIElement」上的拖放装饰器
/// </summary>
/// <param name="viewer">目标「UIElement」对象</param>
/// <param name="dock">画线位置「null」表示画4面框线</param>
public static void UpdateDragAdorner(this UIElement viewer, Dock? dock)
/// <param name="dropPlacement">放置位置或放置模式</param>
/// <param name="parentLayoutDirection">父容器布局方向</param>
public static void UpdateDragAdorner(this UIElement viewer, DropPlacement dropPlacement, LayoutDirection? parentLayoutDirection = null)
{
if (viewer is null) return;
AdornerLayers.Remove(viewer, out var _AdornerLayer);
@@ -52,7 +53,7 @@ namespace Deedy.Activity
_AdornerLayer ??= AdornerLayer.GetAdornerLayer(viewer);
if (_AdornerLayer is null) return;
_DragAdorner = new DragPlacementAdorner(viewer, dock);
_DragAdorner = new DragPlacementAdorner(viewer, dropPlacement, parentLayoutDirection);
_AdornerLayer.Add(_DragAdorner);
AdornerLayers.TryAdd(viewer, _AdornerLayer);

View File

@@ -8,6 +8,7 @@ using System.Windows;
using System.ComponentModel;
using System.Windows.Controls;
using Drawing = System.Drawing;
using System.Windows.Documents;
namespace Deedy.Activity.Helpers
{
@@ -22,13 +23,14 @@ namespace Deedy.Activity.Helpers
/// <param name="ui">要绘制的「UIElement」元素</param>
/// <param name="dc">「UIElement」元素的绘图上下文</param>
/// <param name="dropPlacement">拖放操作的放置位置</param>
/// <param name="parentLayout">父级布局的布局方向</param>
public static void Help_DrawDropAdorner(this UIElement ui, DrawingContext dc, DropPlacement dropPlacement, LayoutDirection parentLayout)
/// <param name="parentLayoutDirection">父级布局的布局方向</param>
public static void Help_DrawDropAdorner(this UIElement ui, DrawingContext dc,
DropPlacement dropPlacement, LayoutDirection? parentLayoutDirection,
Pen? _Pen = null, Brush? _Brush = null)
{
if (ui == null || dc == null || dropPlacement == DropPlacement.UnDragged) return;
Pen pen = new Pen(Brushes.Transparent, 0);
pen.Freeze();
Brush brush = new SolidColorBrush(Colors.Red) { Opacity = 0.5 };
Pen pen = _Pen ?? new Pen(Brushes.Transparent, 0);
Brush brush = _Brush ?? new SolidColorBrush(Colors.Red) { Opacity = 0.5 };
Size size = ui.RenderSize;
ThemeResources res = new();
@@ -42,21 +44,21 @@ namespace Deedy.Activity.Helpers
break;
case DropPlacement.BeforeMe:
{
if (parentLayout == LayoutDirection.Horizontal)
if (parentLayoutDirection == LayoutDirection.Horizontal)
dc.DrawRectangle(brush, pen, new(0, 0, 4, size.Height));
else if (parentLayout == LayoutDirection.Vertical)
else if (parentLayoutDirection == LayoutDirection.Vertical)
dc.DrawRectangle(brush, pen, new(0, 0, size.Width, 4));
else if (parentLayout == LayoutDirection.Stacked)
else if (parentLayoutDirection == LayoutDirection.Stacked)
dc.DrawGeometry(brush, pen, res.DropIcon_BringForward);
}
break;
case DropPlacement.BehindMe:
{
if (parentLayout == LayoutDirection.Horizontal)
if (parentLayoutDirection == LayoutDirection.Horizontal)
dc.DrawRectangle(brush, pen, new(size.Width - 4, 0, 4, size.Height));
else if (parentLayout == LayoutDirection.Vertical)
else if (parentLayoutDirection == LayoutDirection.Vertical)
dc.DrawRectangle(brush, pen, new(size.Height - 4, 0, size.Width, 4));
else if (parentLayout == LayoutDirection.Stacked)
else if (parentLayoutDirection == LayoutDirection.Stacked)
dc.DrawGeometry(brush, pen, res.DropIcon_SendBackward);
}
break;
@@ -72,7 +74,7 @@ namespace Deedy.Activity.Helpers
/// <summary>
/// 检查拖放操作的模式
/// </summary>
/// <param name="ui">要检查的「UIElement」元素</param>
/// <param name="element">要检查的「UIElement」元素</param>
/// <param name="point">检查点位置</param>
/// <returns>检查后的拖放位置其中不包括「DropPlacement.UnDragged」与「DropPlacement.Uncertain」</returns>
/// <remarks>
@@ -80,22 +82,21 @@ namespace Deedy.Activity.Helpers
/// <para>「DropPlacement.Uncertain」= 拖放内容不是可视化元素</para>
/// <para>··以上两种情况需要在调用此方法前进行判定</para>
/// </remarks>
public static DropPlacement Help_CheckDropPlacement(this UIElement ui, Point point)
public static DropPlacement Help_CheckDropPlacement(this IElement element, Size size, Point point)
{
DropPlacement result = DropPlacement.UnDragged;
if (ui != null)
if (element != null)
{
Size size = ui.RenderSize;
double horRuler = size.Width / 3;
if (horRuler > 20) horRuler = 20;
double verRuler = size.Height / 3;
if (verRuler > 20) verRuler = 20;
LayoutDirection direction = LayoutDirection.Cannot;
if (ui is IVisualLayout layout)
if (element is ICombinedElement)
{
if (ui is FrameworkElement fe && fe.Parent is IVisualLayout parentLayout)
if (element.ParentElement is ICombinedElement parentLayout)
{
direction = parentLayout.LayoutDirection;
direction = parentLayout.Direction;
if (direction == LayoutDirection.Decorator)
{
if (point.X < horRuler
@@ -120,9 +121,9 @@ namespace Deedy.Activity.Helpers
}
else
{
if (ui is FrameworkElement fe && fe.Parent is IVisualLayout parentLayout)
if (element.ParentElement is ICombinedElement parentLayout)
{
direction = parentLayout.LayoutDirection;
direction = parentLayout.Direction;
if (direction == LayoutDirection.Decorator)
result = DropPlacement.ReplaceMe;
else if (direction == LayoutDirection.Cannot)