using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media; using System.Windows; using Serein.Workbench.Node.View; using System.Windows.Controls; using Serein.Library; using System.Windows.Data; namespace Serein.Workbench.Node.View { public abstract class NodeJunctionViewBase : ContentControl, IDisposable { public NodeJunctionViewBase() { var transfromGroup = new TransformGroup(); transfromGroup.Children.Add(_Translate); RenderTransform = transfromGroup; } /// /// 每个连接器都有一个唯一标识符(Guid),用于标识连接器。 /// public Guid Guid { get => (Guid)GetValue(GuidProperty); set => SetValue(GuidProperty, value); } public static readonly DependencyProperty GuidProperty = DependencyProperty.Register( nameof(Guid), typeof(Guid), typeof(NodeJunctionViewBase), // NodeConnectorContent new PropertyMetadata(Guid.Empty)); /// /// 连接器当前的连接数,表示有多少条 NodeLink 连接到此连接器。该属性为只读。 /// public int ConnectedCount { get => (int)GetValue(ConnectedCountProperty); private set => SetValue(ConnectedCountPropertyKey, value); } public static readonly DependencyPropertyKey ConnectedCountPropertyKey = DependencyProperty.RegisterReadOnly( nameof(ConnectedCount), typeof(int), typeof(NodeJunctionViewBase), // NodeConnectorContent new PropertyMetadata(0)); public static readonly DependencyProperty ConnectedCountProperty = ConnectedCountPropertyKey.DependencyProperty; /// /// 布尔值,指示此连接器是否有任何连接。 /// public bool IsConnected { get => (bool)GetValue(IsConnectedProperty); private set => SetValue(IsConnectedPropertyKey, value); } public static readonly DependencyPropertyKey IsConnectedPropertyKey = DependencyProperty.RegisterReadOnly( nameof(IsConnected), typeof(bool), typeof(NodeJunctionViewBase), // NodeConnectorContent new PropertyMetadata(false)); public static readonly DependencyProperty IsConnectedProperty = IsConnectedPropertyKey.DependencyProperty; /// /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 /// public Brush Stroke { get => (Brush)GetValue(StrokeProperty); set => SetValue(StrokeProperty, value); } public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register( nameof(Stroke), typeof(Brush), typeof(NodeJunctionViewBase), // NodeConnectorContent new FrameworkPropertyMetadata(Brushes.Blue)); /// /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 /// public double StrokeThickness { get => (double)GetValue(StrokeThicknessProperty); set => SetValue(StrokeThicknessProperty, value); } public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register( nameof(StrokeThickness), typeof(double), typeof(NodeJunctionViewBase), // NodeConnectorContent new FrameworkPropertyMetadata(1.0)); /// /// 这些属性控制连接器的外观(颜色、边框厚度、填充颜色)。 /// public Brush Fill { get => (Brush)GetValue(FillProperty); set => SetValue(FillProperty, value); } public static readonly DependencyProperty FillProperty = DependencyProperty.Register( nameof(Fill), typeof(Brush), typeof(NodeJunctionViewBase),// NodeConnectorContent new FrameworkPropertyMetadata(Brushes.Gray)); /// /// 指示该连接器是否可以与其他连接器进行连接。 /// public bool CanConnect { get => (bool)GetValue(CanConnectProperty); set => SetValue(CanConnectProperty, value); } public static readonly DependencyProperty CanConnectProperty = DependencyProperty.Register( nameof(CanConnect), typeof(bool), typeof(NodeJunctionViewBase),// NodeConnectorContent new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender)); private Point _Position = new Point(); /// /// 该连接器的当前坐标(位置)。 /// public Point Position { get => _Position; set => UpdatePosition(value); } /// /// (重要数据)表示连接器所属的节点。 /// public NodeModelBase NodeModel { get; private set; } = null; /// /// 该连接器所连接的所有 NodeLink 的集合。 /// public IEnumerable NodeLinks => _NodeLinks; List _NodeLinks = new List(); protected abstract FrameworkElement ConnectorControl { get; } TranslateTransform _Translate = new TranslateTransform(); void UpdatePosition(Point pos) { _Position = pos; _Translate.X = _Position.X; _Translate.Y = _Position.Y; InvalidateVisual(); } /// /// 将 NodeLink 添加到连接器,并更新 ConnectedCount 和 IsConnected。 /// /// public void Connect(ConnectionControl nodeLink) { _NodeLinks.Add(nodeLink); ConnectedCount = _NodeLinks.Count; IsConnected = ConnectedCount > 0; } /// /// 断开与某个 NodeLink 的连接,更新连接状态。 /// /// public void Disconnect(ConnectionControl nodeLink) { _NodeLinks.Remove(nodeLink); ConnectedCount = _NodeLinks.Count; IsConnected = ConnectedCount > 0; } /// /// 获取连接器相对于指定 Canvas 的位置。 /// /// /// /// /// public Point GetContentPosition(Canvas canvas, double xScaleOffset = 0.5, double yScaleOffset = 0.5) { // it will be shifted Control position if not called UpdateLayout(). ConnectorControl.UpdateLayout(); var transformer = ConnectorControl.TransformToVisual(canvas); var x = ConnectorControl.ActualWidth * xScaleOffset; var y = ConnectorControl.ActualHeight * yScaleOffset; return transformer.Transform(new Point(x, y)); } /// /// 更新与此连接器相连的所有 NodeLink 的位置。这个方法是抽象的,要求子类实现。 /// /// public abstract void UpdateLinkPosition(Canvas canvas); /// /// 用于检查此连接器是否可以与另一个连接器相连接,要求子类实现。 /// /// /// public abstract bool CanConnectTo(NodeJunctionViewBase connector); /// /// 释放连接器相关的资源,包括样式、绑定和已连接的 NodeLink /// public void Dispose() { // You need to clear Style. // Because implemented on style for binding. Style = null; // Clear binding for subscribing source changed event from old control. // throw exception about visual tree ancestor different if you not clear binding. BindingOperations.ClearAllBindings(this); var nodeLinks = _NodeLinks.ToArray(); // it must instance to nodeLinks because change node link collection in NodeLink Dispose. foreach (var nodeLink in nodeLinks) { // nodeLink.Dispose(); } } } }