Files
serein-flow/Serein.Workbench.Avalonia/Custom/Views/NodeContainerView.axaml.cs

432 lines
13 KiB
C#
Raw Normal View History

2025-01-01 17:49:48 +08:00
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.PanAndZoom;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.VisualTree;
using Newtonsoft.Json.Linq;
using Serein.Library;
using Serein.Library.Utils;
using Serein.Workbench.Avalonia.Api;
using Serein.Workbench.Avalonia.Custom.Node.Views;
2025-01-01 17:49:48 +08:00
using Serein.Workbench.Avalonia.Custom.ViewModels;
using Serein.Workbench.Avalonia.Extension;
using Serein.Workbench.Avalonia.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using Point = Avalonia.Point;
namespace Serein.Workbench.Avalonia.Custom.Views;
public partial class NodeContainerView : UserControl
{
private readonly NodeContainerViewModel _vm;
private readonly INodeOperationService nodeOperationService;
private readonly IKeyEventService keyEventService;
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><EFBFBD>ֶ<EFBFBD>
/// <summary>
/// <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>Ԥ<EFBFBD><D4A4><EFBFBD>ڵ<EFBFBD><DAB5>ؼ<EFBFBD>
/// </summary>
private bool IsPreviewNodeControl;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ڳ<EFBFBD><DAB3><EFBFBD>ѡȡ<D1A1>ؼ<EFBFBD>
/// </summary>
private bool IsSelectControl;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6>ؼ<EFBFBD>
/// </summary>
private bool IsControlDragging;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
private bool IsCanvasDragging;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD>ѡȡ<D1A1>ڵ<EFBFBD>
/// </summary>
private bool IsSelectDragging;
/// <summary>
/// <20><>ǰѡȡ<D1A1>Ŀؼ<C4BF>
/// </summary>
private readonly List<NodeControlBase> selectNodeControls = [];
2025-01-01 17:49:48 +08:00
/// <summary>
/// <20><>¼<EFBFBD><C2BC>ʼ<EFBFBD>϶<EFBFBD><CFB6>ڵ<EFBFBD><DAB5>ؼ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
/// </summary>
private Point startControlDragPoint;
/// <summary>
/// <20><>¼<EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼʱ<CABC><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
/// </summary>
private Point startCanvasDragPoint;
/// <summary>
/// <20><>¼<EFBFBD><C2BC>ʼѡȡ<D1A1>ڵ<EFBFBD><DAB5>ؼ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
/// </summary>
private Point startSelectControolPoint;
/// <summary>
/// <20><><EFBFBD>ϱ<CFB1><E4BBBB><EFBFBD><EFBFBD>
/// </summary>
private readonly TransformGroup canvasTransformGroup;
/// <summary>
/// <20><><EFBFBD>Ż<EFBFBD><C5BB><EFBFBD>
/// </summary>
private readonly ScaleTransform scaleTransform;
/// <summary>
/// ƽ<>ƻ<EFBFBD><C6BB><EFBFBD>
/// </summary>
private readonly TranslateTransform translateTransform;
#endregion
public NodeContainerView()
{
InitializeComponent();
_vm= App.GetService<NodeContainerViewModel>();
DataContext = _vm;
#region <EFBFBD><EFBFBD>ȡUI<EFBFBD><EFBFBD><EFBFBD>صķ<EFBFBD><EFBFBD><EFBFBD>
keyEventService = App.GetService<IKeyEventService>();
nodeOperationService = App.GetService<INodeOperationService>();
nodeOperationService.MainCanvas = PART_NodeContainer;
nodeOperationService.OnNodeViewCreate += NodeOperationService_OnNodeViewCreate; // <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
keyEventService.KeyUp += (k) =>
{
if (k == Key.Escape)
{
IsCanvasDragging = false;
IsControlDragging = false;
nodeOperationService.ConnectingManage.Reset();
2025-01-01 17:49:48 +08:00
}
};
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD>UI<EFBFBD>¼<EFBFBD>
AddHandler(DragDrop.DropEvent, Drop); // <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
PointerPressed += NodeContainerView_PointerPressed;
PointerReleased += NodeContainerView_PointerReleased;
PointerMoved += NodeContainerView_PointerMoved;
PointerWheelChanged += NodeContainerView_PointerWheelChanged;
#endregion
#region <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
canvasTransformGroup = new TransformGroup();
scaleTransform = new ScaleTransform();
translateTransform = new TranslateTransform();
canvasTransformGroup.Children.Add(scaleTransform);
canvasTransformGroup.Children.Add(translateTransform);
PART_NodeContainer.RenderTransform = canvasTransformGroup;
#endregion
}
#region <EFBFBD><EFBFBD><EFBFBD>߷<EFBFBD><EFBFBD><EFBFBD>
public Point GetPositionOfCanvas(PointerEventArgs e)
{
return e.GetPosition(PART_NodeContainer);
}
public Point GetPositionOfCanvas(DragEventArgs e)
{
return e.GetPosition(PART_NodeContainer);
}
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>š<EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD>ק<EFBFBD>¼<EFBFBD>
#region <EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD>ק<EFBFBD>¼<EFBFBD>
private void Drop(object? sender, DragEventArgs e)
{
if (e.Data.Contains(DataFormats.Text))
{
var json = e.Data.GetText();
if (string.IsNullOrEmpty(json))
{
return;
}
var mdInfo = json.ToJsonObject<MethodDetailsInfo>();
if (mdInfo is not null)
{
var canvasDropPosition = GetPositionOfCanvas(e); // <20><><EFBFBD>»<EFBFBD><C2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
PositionOfUI position = new PositionOfUI(canvasDropPosition.X, canvasDropPosition.Y);
nodeOperationService.CreateNodeView(mdInfo, position); // <20><EFBFBD><E1BDBB><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
}
else // if (e.Data.Contains(DataFormats.FileNames))
{
var files = e.Data.GetFiles();
var str = files?.Select(f => f.Path);
if (str is not null)
{
}
}
}
#endregion
#region <EFBFBD>϶<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
private void NodeContainerView_PointerPressed(object? sender, PointerPressedEventArgs e)
{
if (IsPreviewNodeControl)
{
IsCanvasDragging = false;
e.Handled = true;
return;
}
if (!IsCanvasDragging)
{
IsCanvasDragging = true;
startCanvasDragPoint = e.GetPosition(this);
e.Handled = true;
}
}
private void NodeContainerView_PointerReleased(object? sender, PointerReleasedEventArgs e)
{
IsCanvasDragging = false; // <20><><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD>
}
private void NodeContainerView_PointerMoved(object? sender, PointerEventArgs e)
{
// <20>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var myData = nodeOperationService.ConnectingManage;
2025-01-01 17:49:48 +08:00
if (myData.IsCreateing)
{
var isPass = e.JudgePointer(sender, PointerType.Mouse, p => p.IsLeftButtonPressed);
if (isPass)
{
if (myData.Type == JunctionOfConnectionType.Invoke)
{
_vm.IsConnectionInvokeNode = true; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӽڵ<D3BD><DAB5>ĵ<EFBFBD><C4B5>ù<EFBFBD>ϵ
}
else
{
_vm.IsConnectionArgSourceNode = true; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӽڵ<D3BD><DAB5>ĵ<EFBFBD><C4B5>ù<EFBFBD>ϵ
}
var currentPoint = e.GetPosition(PART_NodeContainer);
//myData.CurrentJunction?.InvalidateVisual();
2025-01-01 17:49:48 +08:00
myData.UpdatePoint(new Point(currentPoint.X - 5, currentPoint.Y - 5));
e.Handled = true;
2025-01-01 17:49:48 +08:00
return;
}
}
if (IsCanvasDragging)
{
// <20>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD>
Point currentMousePosition = e.GetPosition(this);
double deltaX = currentMousePosition.X - startCanvasDragPoint.X;
double deltaY = currentMousePosition.Y - startCanvasDragPoint.Y;
translateTransform.X += deltaX;
translateTransform.Y += deltaY;
startCanvasDragPoint = currentMousePosition;
}
}
// <20><><EFBFBD><EFBFBD>
private void NodeContainerView_PointerWheelChanged(object? sender, PointerWheelEventArgs e)
{
var delta = e.Delta.Y;
if (delta < 0 && scaleTransform.ScaleX < 0.02) return;
if (delta > 0 && scaleTransform.ScaleY > 4.0) return;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӣ<EFBFBD><D3A3><EFBFBD><EFBFBD>ݹ<EFBFBD><DDB9>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double zoomFactor = delta > 0 ? 1.23 : 0.78;
// <20><>ǰ<EFBFBD><C7B0><EFBFBD>ű<EFBFBD><C5B1><EFBFBD>
double oldScale = scaleTransform.ScaleX;
double newScale = oldScale * zoomFactor;
// <20><>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
var mousePosition = GetPositionOfCanvas(e);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD>
scaleTransform.ScaleX = newScale;
scaleTransform.ScaleY = newScale;
// <20><>¼<EFBFBD><C2BC><EFBFBD>ź<EFBFBD><C5BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
var newMousePosition = GetPositionOfCanvas(e);
// <20><><EFBFBD><EFBFBD> TranslateTransform<72><6D>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>Ϊ<EFBFBD><CEAA><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var s_position = newMousePosition - mousePosition; // <20><><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
translateTransform.X += s_position.X * newScale; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB>
translateTransform.Y += s_position.Y * newScale; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB>
}
#endregion
#endregion
#region <EFBFBD>ڵ<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD><EFBFBD><EFBFBD>
/// <summary>
/// <20><>ק<EFBFBD><D7A7><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>
/// </summary>
/// <param name="eventArgs"></param>
/// <returns></returns>
private bool NodeOperationService_OnNodeViewCreate(NodeViewCreateEventArgs eventArgs)
{
if (eventArgs.NodeControl is not Control control)
{
return false;
}
var position = eventArgs.Position;// <20><><EFBFBD><EFBFBD>
SetNodeEvent(control); // <20><><EFBFBD>øÿؼ<C3BF><D8BC><EFBFBD><EBBBAD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
DragControl(control, position.X, position.Y);
PART_NodeContainer.Children.Add(control);
return true;
}
/// <summary>
/// <20><><EFBFBD>ýڵ<C3BD><DAB5><EFBFBD><EBBBAD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>صIJ<D8B5><C4B2><EFBFBD><EFBFBD>¼<EFBFBD>
/// </summary>
/// <param name="nodeControl"></param>
private void SetNodeEvent(Control nodeControl)
{
nodeControl.PointerMoved += NodeControl_PointerMoved; ;
nodeControl.PointerExited += NodeControl_PointerExited;
nodeControl.PointerPressed += Block_MouseLeftButtonDown;
nodeControl.PointerMoved += Block_MouseMove;
nodeControl.PointerReleased += (s, e) => IsControlDragging = false;
}
#endregion
#region <EFBFBD>ؼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ط<EFBFBD><EFBFBD><EFBFBD>
/// <summary>
/// <20>ƶ<EFBFBD><C6B6>ؼ<EFBFBD>
/// </summary>
/// <param name="nodeControl"></param>
/// <param name="x"></param>
/// <param name="y"></param>
private void DragControl(Control nodeControl, double x, double y)
{
Canvas.SetLeft(nodeControl, x);
Canvas.SetTop(nodeControl, y);
}
/// <summary>
/// <20>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҽ<EFBFBD><D2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
2025-01-01 17:49:48 +08:00
/// </summary>
private void Block_MouseLeftButtonDown(object? sender, PointerPressedEventArgs e)
{
var isPass = e.JudgePointer(sender, PointerType.Mouse, p => p.IsRightButtonPressed);
if (!isPass)
{
return;
}
if (sender is NodeControlBase nodeControl)
2025-01-01 17:49:48 +08:00
{
IsControlDragging = true;
startControlDragPoint = GetPositionOfCanvas(e); // <20><>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EAB0B4>ʱ<EFBFBD><CAB1>λ<EFBFBD><CEBB>
2025-01-01 17:49:48 +08:00
e.Handled = true; // <20><>ֹ<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>
}
}
/// <summary>
/// <20>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>¿ؼ<C2BF><D8BC><EFBFBD>λ<EFBFBD>á<EFBFBD><C3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6>߼<EFBFBD><DFBC><EFBFBD>
/// </summary>
private void Block_MouseMove(object? sender, PointerEventArgs e)
{
if (sender is not NodeControlBase nodeControl)
2025-01-01 17:49:48 +08:00
{
return;
}
if (IsCanvasDragging)
return;
if (IsSelectControl)
return;
if (IsControlDragging) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6>ؼ<EFBFBD>
{
Point currentPosition = GetPositionOfCanvas(e); // <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
// <20><><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>
if (selectNodeControls.Count == 0 || !selectNodeControls.Contains(nodeControl))
{
double deltaX = currentPosition.X - startControlDragPoint.X; // <20><><EFBFBD><EFBFBD>X<EFBFBD><EFBFBD><E1B7BD><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
double deltaY = currentPosition.Y - startControlDragPoint.Y; // <20><><EFBFBD><EFBFBD>Y<EFBFBD><EFBFBD><E1B7BD><EFBFBD><EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
double newLeft = Canvas.GetLeft(nodeControl) + deltaX; // <20>µ<EFBFBD><C2B5><EFBFBD><EFBFBD>߾<EFBFBD>
double newTop = Canvas.GetTop(nodeControl) + deltaY; // <20>µ<EFBFBD><C2B5>ϱ߾<CFB1>
DragControl(nodeControl, newLeft, newTop);
nodeControl.UpdateLocationConnections();
2025-01-01 17:49:48 +08:00
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>
else
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>
// <20><>ȡ<EFBFBD><C8A1>λ<EFBFBD><CEBB>
var oldLeft = Canvas.GetLeft(nodeControl);
var oldTop = Canvas.GetTop(nodeControl);
// <20><><EFBFBD>ѡ<E3B1BB><D1A1><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD>ƫ<EFBFBD><C6AB><EFBFBD><EFBFBD>
var deltaX = /*(int)*/(currentPosition.X - startControlDragPoint.X);
var deltaY = /*(int)*/(currentPosition.Y - startControlDragPoint.Y);
// <20>ƶ<EFBFBD><C6B6><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD>Ŀؼ<C4BF>
var newLeft = oldLeft + deltaX;
var newTop = oldTop + deltaY;
//this.EnvDecorator.MoveNode(nodeControlMain.ViewModel.NodeModel.Guid, newLeft, newTop); // <20>ƶ<EFBFBD><C6B6>ڵ<EFBFBD>
DragControl(nodeControl, newLeft, newTop);
// <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD>ƶ<EFBFBD><C6B6>ľ<EFBFBD><C4BE><EFBFBD>
var actualDeltaX = newLeft - oldLeft;
var actualDeltaY = newTop - oldTop;
// <20>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD>еĿؼ<C4BF>
foreach (var selectItemNode in selectNodeControls)
{
if (selectItemNode != nodeControl) // <20><><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE>ƶ<EFBFBD><C6B6>Ŀؼ<C4BF>
{
var otherNewLeft = Canvas.GetLeft(selectItemNode) + actualDeltaX;
var otherNewTop = Canvas.GetTop(selectItemNode) + actualDeltaY;
DragControl(selectItemNode, otherNewLeft, otherNewTop);
//this.EnvDecorator.MoveNode(nodeControl.ViewModel.NodeModel.Guid, otherNewLeft, otherNewTop); // <20>ƶ<EFBFBD><C6B6>ڵ<EFBFBD>
}
}
// <20><><EFBFBD>½ڵ<C2BD>֮<EFBFBD><D6AE><EFBFBD>ߵ<EFBFBD><DFB5><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
foreach (var item in selectNodeControls)
{
item.UpdateLocationConnections();
}
2025-01-01 17:49:48 +08:00
}
startControlDragPoint = currentPosition; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>λ<EFBFBD><CEBB>
}
}
private void NodeControl_PointerExited(object? sender, PointerEventArgs e)
{
IsPreviewNodeControl = false;
}
private void NodeControl_PointerMoved(object? sender, PointerEventArgs e)
{
IsPreviewNodeControl = true;
}
#endregion
}