using Serein.Library; using Serein.Library.Api; using Serein.Workbench.Node.ViewModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; namespace Serein.Workbench.Node.View { /// /// 节点控件基类(控件) /// public abstract class NodeControlBase : UserControl, IDynamicFlowNode { /// /// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能) /// public Canvas NodeCanvas { get; set; } private INodeContainerControl nodeContainerControl; /// /// 如果该节点放置在了某个容器节点,就会记录这个容器节点 /// private INodeContainerControl NodeContainerControl { get; } /// /// 记录与该节点控件有关的所有连接 /// private readonly List connectionControls = new List(); public NodeControlViewModelBase ViewModel { get; set; } protected NodeControlBase() { this.Background = Brushes.Transparent; } protected NodeControlBase(NodeControlViewModelBase viewModelBase) { ViewModel = viewModelBase; this.Background = Brushes.Transparent; this.DataContext = viewModelBase; SetBinding(); } /// /// 放置在某个节点容器中 /// public void PlaceToContainer(INodeContainerControl nodeContainerControl) { this.nodeContainerControl = nodeContainerControl; NodeCanvas.Children.Remove(this); // 临时从画布上移除 var result = nodeContainerControl.PlaceNode(this); if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来 { NodeCanvas.Children.Add(this); // 从画布上移除 } } /// /// 从某个节点容器取出 /// public void TakeOutContainer() { var result = nodeContainerControl.TakeOutNode(this); // 从控件取出 if (result) // 移除成功时才添加到画布上 { NodeCanvas.Children.Add(this); // 重新添加到画布上 if (nodeContainerControl is NodeControlBase containerControl) { this.ViewModel.NodeModel.Position.X = containerControl.ViewModel.NodeModel.Position.X + containerControl.Width + 10; this.ViewModel.NodeModel.Position.Y = containerControl.ViewModel.NodeModel.Position.Y; } } } /// /// 添加与该节点有关的连接后,记录下来 /// /// public void AddCnnection(ConnectionControl connection) { connectionControls.Add(connection); } /// /// 删除了连接之后,还需要从节点中的记录移除 /// /// public void RemoveConnection(ConnectionControl connection) { connectionControls.Remove(connection); connection.Remote(); } /// /// 删除所有连接 /// public void RemoveAllConection() { foreach (var connection in this.connectionControls) { connection.Remote(); } } /// /// 更新与该节点有关的数据 /// public void UpdateLocationConnections() { foreach (var connection in this.connectionControls) { connection.RefreshLine(); // 主动更新连线位置 } } /// /// 设置绑定: /// Canvas.X and Y : 画布位置 /// public void SetBinding() { // 绑定 Canvas.Left Binding leftBinding = new Binding("X") { Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中 Mode = BindingMode.TwoWay }; BindingOperations.SetBinding(this, Canvas.LeftProperty, leftBinding); // 绑定 Canvas.Top Binding topBinding = new Binding("Y") { Source = ViewModel.NodeModel.Position, // 如果 Y 属性在当前 DataContext 中 Mode = BindingMode.TwoWay }; BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding); } /// /// 穿透视觉树获取指定类型的第一个元素 /// /// /// /// protected T FindVisualChild(DependencyObject parent) where T : DependencyObject { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) { var child = VisualTreeHelper.GetChild(parent, i); if (child is T typedChild) { return typedChild; } var childOfChild = FindVisualChild(child); if (childOfChild != null) { return childOfChild; } } return null; } } //public class FLowNodeObObservableCollection : ObservableCollection //{ // public void AddRange(IEnumerable items) // { // foreach (var item in items) // { // this.Items.Add(item); // } // OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add)); // } //} }