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

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

View File

@@ -7,65 +7,34 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Media; using System.Windows.Media;
using Deedy.Activity.Helpers;
namespace Deedy.Activity namespace Deedy.Activity
{ {
public class DragPlacementAdorner : Adorner public class DragPlacementAdorner : Adorner
{ {
private static readonly Pen _PrevPen; private static readonly Pen _Pen;
private static readonly Pen _NextPen; private static readonly Brush _Brush;
private static readonly Pen _PartPen; public DropPlacement DropPlacement { get; private set; }
public Dock? Position { get; private set; } public LayoutDirection? LayoutDirection { get; private set; }
static DragPlacementAdorner() static DragPlacementAdorner()
{ {
// 定义装饰器的画笔 // 定义装饰器的画笔与画刷
_PrevPen = new Pen(Brushes.Red, 5.0); _Pen = new Pen(Brushes.Transparent, 0);
_PrevPen.Freeze(); _Pen.Freeze();
_NextPen = new Pen(Brushes.Red, 5.0); _Brush = new SolidColorBrush(Colors.Red) { Opacity = 0.5 };
_NextPen.Freeze(); _Brush.Freeze();
_PartPen = new Pen(Brushes.Blue, 3.0);
_PartPen.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; IsHitTestVisible = false;
} }
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
{ => this.Help_DrawDropAdorner(drawingContext, this.DropPlacement, this.LayoutDirection, _Pen, _Brush);
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;
}
}
} }
} }

View File

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

View File

@@ -11,5 +11,6 @@ namespace Deedy.Activity
public CombinedLogical() { } public CombinedLogical() { }
public ElementCollection Elements { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 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 ContainerLogical() { }
public abstract ElementCollection Elements { get; set; } 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 void Append(IElement element);
public abstract bool CombineChecking(IElement element, out DragDropEffects effects); public abstract bool CombineChecking(IElement element, out DragDropEffects effects);

View File

@@ -11,5 +11,6 @@ namespace Deedy.Activity
public CombinedFunction() { } public CombinedFunction() { }
public ElementCollection Elements { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 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 ContainerFunction() { }
public abstract ElementCollection Elements { get; set; } 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 void Append(IElement element);
public abstract bool CombineChecking(IElement element, out DragDropEffects effects); public abstract bool CombineChecking(IElement element, out DragDropEffects effects);

View File

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

View File

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

View File

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

View File

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