using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Documents; namespace AIStudio.Wpf.DiagramDesigner { public static partial class BlockDesignerItemViewModelHelper { /// /// type=0最近且没有依附;=1 /// /// /// /// public static Tuple FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink) { if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.LinkList == null || blockDesignerItemTempLink.LinkList.Count == 0) return new Tuple(null, null); List items = diagramViewModel.Items.OfType().Where(p => !blockDesignerItemTempLink.LinkList.Contains(p)).ToList(); return diagramViewModel.FindNearPortToAttachTo(items, blockDesignerItemTempLink); } public static Tuple FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, List items, BlockDesignerItemTempLink blockDesignerItemTempLink) { if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.LinkList == null || blockDesignerItemTempLink.LinkList.Count == 0) return new Tuple(null, null); FullyCreatedConnectorInfo parent = null; FullyCreatedConnectorInfo next = null; foreach (var port2 in blockDesignerItemTempLink.Connectors.OfType()) { bool success = false; foreach (var item in items) { foreach (var port in item.Connectors.OfType()) { //已经被连接的不允许在顶部吸附了 if ((port.Orientation == ConnectorOrientation.Top || port.Orientation == ConnectorOrientation.Left) && port.DataItem.LinkNode.Previous != null) { continue; } //parent if (parent == null) { if ((port.Orientation == ConnectorOrientation.Right && port2.Orientation == ConnectorOrientation.Left) || (port.Orientation == ConnectorOrientation.Bottom && port2.Orientation == ConnectorOrientation.Top)) { var dis = port.DistanceTo(port2); //Debug.WriteLine($"{port.DataItem.Name}-{port2.DataItem.Name}:{dis}"); if (dis < diagramViewModel.DiagramOption.SnappingOption.BlockSnappingRadius) { port.DataItem.ShowConnectors = true; if (port.CanAttachTo(port2) == true) { diagramViewModel.AddAttachTo(port, true); parent = port; success = true; break; } else { diagramViewModel.AddAttachTo(port, false); } } } } //next if (next == null) { if ((port.Orientation == ConnectorOrientation.Left && port2.Orientation == ConnectorOrientation.Right) || (port.Orientation == ConnectorOrientation.Top && port2.Orientation == ConnectorOrientation.Bottom)) { var dis = port.DistanceTo(port2); //Debug.WriteLine($"{port.DataItem.Name}-{port2.DataItem.Name}:{dis}"); if (dis < diagramViewModel.DiagramOption.SnappingOption.BlockSnappingRadius) { port.DataItem.ShowConnectors = true; if (port.CanAttachTo(port2) == true) { diagramViewModel.AddAttachTo(port, true); next = port; success = true; break; } else { diagramViewModel.AddAttachTo(port, false); } } } } } if (success) { break; } } if (success) { break; } } return new Tuple(parent, next); } public static BlockItemsContainerInfo FindNearContainerToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink) { if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.LinkList == null || blockDesignerItemTempLink.LinkList.Count == 0) return null; List items; items = diagramViewModel.Items.OfType().Where(p => !blockDesignerItemTempLink.LinkList.Contains(p)).ToList(); foreach (var container in items.SelectMany(n => n.Containers)) { if (container.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())) //如果两个位置相交 { var innerport = container.GetAllContainers(container.Children, false).Where(p => p.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())).OrderByDescending(p => p.ContainerLevel).FirstOrDefault(); if (innerport != null) { if (innerport.CanAttachTo(blockDesignerItemTempLink.LinkList.FirstOrDefault()) == true) { innerport.DataItem.ShowConnectors = true; if (innerport.OnlyOneChild || innerport.Children.Count == 0) { diagramViewModel.AddAttachTo(innerport, true); } else { diagramViewModel.FindNearPortToAttachTo(innerport.Children.ToList(), blockDesignerItemTempLink); } return innerport; } //else //{ // innerport.DisableAttachTo = true; // return null; //} } else { if (container.CanAttachTo(blockDesignerItemTempLink.LinkList.FirstOrDefault()) == true) { container.DataItem.ShowConnectors = true; if (container.OnlyOneChild || container.Children.Count == 0) { diagramViewModel.AddAttachTo(container, true); } else { diagramViewModel.FindNearPortToAttachTo(container.Children.ToList(), blockDesignerItemTempLink); } return container; } //else //{ // port.DisableAttachTo = true; // return null; //} } } } return null; } #region Block拖拽预览-拖拽完成 public static void PreviewNearBlock(this IBlockDiagramViewModel diagramViewModel, List blocks) { if (diagramViewModel == null) return; if (blocks.Any()) { diagramViewModel.ClearAttachTo(); var links = BlockDesignerItemTempLink.Build(blocks); blocks.ToList().ForEach(p => { if (p.ZIndex != int.MaxValue) { p.SetOldValue(p.ZIndex, "ZIndex"); } p.ZIndex = int.MaxValue; }); foreach (BlockDesignerItemTempLink item in links) { var container = diagramViewModel.FindNearContainerToAttachTo(item); if (container != null) { continue; } diagramViewModel.FindNearPortToAttachTo(item); } } } public static void FinishNearBlock(this IBlockDiagramViewModel diagramViewModel, List blocks) { if (diagramViewModel == null) return; if (blocks.Any()) { var links = BlockDesignerItemTempLink.Build(blocks); blocks.ToList().ForEach(p => { if (p.HasOldValue("ZIndex")) { p.ZIndex = p.GetOldValue("ZIndex"); } }); foreach (BlockDesignerItemTempLink item in links) { var container = diagramViewModel.FindNearContainerToAttachTo(item); if (container != null) { int index = 0; var child = container.Children.FirstOrDefault(p => p.Connectors.Any(q => q.BeAttachTo == true)); if (child != null) { index = container.Children.IndexOf(child); if (child.RightConnector?.BeAttachTo == true || child.BottomConnector?.BeAttachTo == true) { index++; } } diagramViewModel.InsertChildCommand.Execute(new BlockContainerPara() { Item = container.DataItem, Child = item.LinkList.FirstOrDefault(), Container = container, Index = index }); continue; } var portTuple = diagramViewModel.FindNearPortToAttachTo(item); var portParent = portTuple.Item1; var portNext = portTuple.Item2; if (portParent != null) { diagramViewModel.AddNextCommand.Execute(new BlockNextPara() { Item = portParent.DataItem as BlockDesignerItemViewModel, Next = item.LinkList.FirstOrDefault() }); portParent.BeAttachTo = false; portParent.DisableAttachTo = false; } else if (portNext != null) { diagramViewModel.AddNextCommand.Execute(new BlockNextPara() { First = item.LinkList.FirstOrDefault(), Item = item.LinkList.LastOrDefault(), Next = portNext.DataItem as BlockDesignerItemViewModel }); portNext.BeAttachTo = false; portNext.DisableAttachTo = false; } else { if (item.LinkList.FirstOrDefault().LinkNode.Previous != null) { diagramViewModel.RemoveNextCommand.Execute(new BlockNextPara() { Item = item.LinkList.FirstOrDefault().LinkNode.Previous.Value, Next = item.LinkList.FirstOrDefault().LinkNode.Value }); } } } diagramViewModel.ClearAttachTo(); } } #endregion } public static class LinkedListExtensions { public static void InsertRange(this LinkedList source, LinkedListNode node, IEnumerable items) { if (node == null || items.Count() == 0) { return; } BlockDesignerItemViewModel last = null; foreach (var item in items) { item.LinkNode = source.AddAfter(node, item); item.ParentId = item.LinkNode.Previous.Value.Id; node = item.LinkNode; last = item; } //把后面的接上 var lastnode = source.Find(last); if (lastnode.Next != null) { lastnode.Next.Value.ParentId = last.Id; } } public static void AppendRange(this LinkedList source, IEnumerable items) { foreach (var item in items) { item.LinkNode = source.AddLast(item); item.ParentId = item.LinkNode.Previous?.Value.Id ?? new Guid(); } } public static void PrependRange(this LinkedList source, IEnumerable items) { var first = source.First; // If the list is empty, we can just append everything. if (first is null) { AppendRange(source, items); return; } // Otherwise, add each item in turn just before the original first item foreach (var item in items) { item.LinkNode = source.AddBefore(first, item); item.ParentId = item.LinkNode.Previous.Value.Id; } } } }