using System; using System.Collections.Generic; using System.Linq; using System.Text; using AIStudio.Wpf.DiagramDesigner.Geometrys; namespace AIStudio.Wpf.DiagramDesigner { public static class DiagramViewModelHelper { public static DesignerItemViewModelBase GetConnectorDataItem(IEnumerable items, Guid conectorDataItemId, Type connectorDataItemType) { DesignerItemViewModelBase dataItem = items.OfType().Single(x => x.Id == conectorDataItemId); return dataItem; } public static RectangleBase GetBoundingRectangle(IEnumerable items) { double x1 = Double.MaxValue; double y1 = Double.MaxValue; double x2 = Double.MinValue; double y2 = Double.MinValue; foreach (DesignerItemViewModelBase item in items) { x1 = Math.Min(item.Left, x1); y1 = Math.Min(item.Top, y1); x2 = Math.Max(item.Left + item.GetItemWidth(), x2); y2 = Math.Max(item.Top + item.GetItemHeight(), y2); } return new RectangleBase(new PointBase(x1, y1), new PointBase(x2, y2)); } public static RectangleBase GetBoundingRectangle(DesignerItemViewModelBase item) { return GetBoundingRectangle(new DesignerItemViewModelBase[] { item }); } #region 自动依附节点 public static FullyCreatedConnectorInfo FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, ConnectionViewModel partialConnection, ConnectorVertexType connectorVertexType) { if (partialConnection == null) return null; diagramViewModel.ClearNearPort(); foreach (var port in diagramViewModel.Items.OfType().ToList().SelectMany(n => n.Connectors)) { if (connectorVertexType == ConnectorVertexType.Start) { if (partialConnection.SourceConnectorInfo.Position.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { if (partialConnection.SinkConnectorInfo?.CanAttachTo(port) == true) { port.DataItem.ShowConnectors = true; port.BeAttachTo = true; return port; } else { port.DataItem.ShowConnectors = true; port.DisableAttachTo = true; return null; } } } else if (connectorVertexType == ConnectorVertexType.End) { if (partialConnection.SinkConnectorInfo.Position.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true) { port.DataItem.ShowConnectors = true; port.BeAttachTo = true; return port; } else { port.DataItem.ShowConnectors = true; port.DisableAttachTo = true; return null; } } } } return null; } public static FullyCreatedConnectorInfo FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, ConnectionViewModel partialConnection) { if (partialConnection == null) return null; diagramViewModel.ClearNearPort(); foreach (var port in diagramViewModel.Items.OfType().ToList().SelectMany(n => n.Connectors)) { if (partialConnection.OnGoingPosition.DistanceTo(port.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { port.DataItem.ShowConnectors = true; if (partialConnection.SourceConnectorInfo?.CanAttachTo(port) == true) { port.BeAttachTo = true; return port; } else { port.DisableAttachTo = true; return null; } } } return null; } /// /// type=0最近且没有依附;=1 /// /// /// /// public static Tuple FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemViewModel blockDesignerItemViewModel, bool isExist) { if (blockDesignerItemViewModel == null) return new Tuple(null, null); List items; if (isExist == false) { items = diagramViewModel.Items.OfType(). Where(p => p != blockDesignerItemViewModel && p != blockDesignerItemViewModel.Parent && p != blockDesignerItemViewModel.Next) .ToList(); } else { items = diagramViewModel.Items.OfType(). Where(p => p != blockDesignerItemViewModel) .ToList(); } FullyCreatedConnectorInfo parent = null; FullyCreatedConnectorInfo next = null; foreach (var port in items.SelectMany(n => n.Connectors)) { foreach (var port2 in blockDesignerItemViewModel.Connectors) { //parent if (parent == null) { if ((port.Orientation == ConnectorOrientation.Right && port2.Orientation == ConnectorOrientation.Left) || (port.Orientation == ConnectorOrientation.Bottom && port2.Orientation == ConnectorOrientation.Top)) { if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { port.DataItem.ShowConnectors = true; if (port2.CanAttachTo(port) == true) { port.BeAttachTo = true; parent = port; continue; } else { port.DisableAttachTo = true; } } } } //next if (next == null) { if ((port.Orientation == ConnectorOrientation.Left && port2.Orientation == ConnectorOrientation.Right) || (port.Orientation == ConnectorOrientation.Top && port2.Orientation == ConnectorOrientation.Bottom)) { if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { port.DataItem.ShowConnectors = true; if (port2.CanAttachTo(port) == true) { port.BeAttachTo = true; next = port; continue; } else { port.DisableAttachTo = true; } } } } } } return new Tuple(parent, next); } public static BlockItemsContainerInfo FindNearContainerToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemViewModel blockDesignerItemViewModel) { if (blockDesignerItemViewModel == null) return null; List items; items = diagramViewModel.Items.OfType(). Where(p => p != blockDesignerItemViewModel) .ToList(); foreach (var port in items.SelectMany(n => n.Containers)) { if (port.GetBounds().IntersectsWith(blockDesignerItemViewModel.GetBounds())) //如果两个位置相交 { var innerport = port.GetAllContainers(port.Children, false).Where(p => p.GetBounds().IntersectsWith(blockDesignerItemViewModel.GetBounds())).OrderByDescending(p => p.ContainerLevel).FirstOrDefault(); if (innerport != null) { innerport.DataItem.ShowConnectors = true; if (innerport.CanAttachTo(blockDesignerItemViewModel) == true) { innerport.BeAttachTo = true; } else { innerport.DisableAttachTo = true; } return innerport; } else { port.DataItem.ShowConnectors = true; if (port.CanAttachTo(blockDesignerItemViewModel) == true) { port.BeAttachTo = true; } else { port.DisableAttachTo = true; } return port; } } } return null; } /// /// type=0最近且没有依附;=1 /// /// /// /// public static Tuple FindNearPortToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink, bool isExist) { if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.Items == null || blockDesignerItemTempLink.Items.Count == 0) return new Tuple(null, null); List items; if (isExist == false) { items = diagramViewModel.Items.OfType().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList(); } else { items = diagramViewModel.Items.OfType().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList(); } FullyCreatedConnectorInfo parent = null; FullyCreatedConnectorInfo next = null; foreach (var port in items.SelectMany(n => n.Connectors).OfType()) { //已经被连接的不允许在顶部吸附了 if ((port.Orientation == ConnectorOrientation.Top || port.Orientation == ConnectorOrientation.Left) && port.DataItem.Prev != null) { continue; } foreach (var port2 in blockDesignerItemTempLink.Connectors) { //parent if (parent == null) { if ((port.Orientation == ConnectorOrientation.Right && port2.Orientation == ConnectorOrientation.Left) || (port.Orientation == ConnectorOrientation.Bottom && port2.Orientation == ConnectorOrientation.Top)) { if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { port.DataItem.ShowConnectors = true; if (port2.CanAttachTo(port) == true) { port.BeAttachTo = true; parent = port; continue; } else { port.DisableAttachTo = true; } } } } //next if (next == null) { if ((port.Orientation == ConnectorOrientation.Left && port2.Orientation == ConnectorOrientation.Right) || (port.Orientation == ConnectorOrientation.Top && port2.Orientation == ConnectorOrientation.Bottom)) { if (port.Position.DistanceTo(port2.Position) < diagramViewModel.DiagramOption.SnappingOption.SnappingRadius) { port.DataItem.ShowConnectors = true; if (port2.CanAttachTo(port) == true) { port.BeAttachTo = true; next = port; continue; } else { port.DisableAttachTo = true; } } } } } } return new Tuple(parent, next); } public static BlockItemsContainerInfo FindNearContainerToAttachTo(this IDiagramViewModel diagramViewModel, BlockDesignerItemTempLink blockDesignerItemTempLink) { if (blockDesignerItemTempLink == null || blockDesignerItemTempLink.Items == null || blockDesignerItemTempLink.Items.Count == 0) return null; List items; items = diagramViewModel.Items.OfType().Where(p => !blockDesignerItemTempLink.Items.Contains(p)).ToList(); foreach (var port in items.SelectMany(n => n.Containers)) { if (port.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())) //如果两个位置相交 { var innerport = port.GetAllContainers(port.Children, false).Where(p => p.GetBounds().IntersectsWith(blockDesignerItemTempLink.GetBounds())).OrderByDescending(p => p.ContainerLevel).FirstOrDefault(); if (innerport != null) { innerport.DataItem.ShowConnectors = true; if (innerport.CanAttachTo(blockDesignerItemTempLink.Items.FirstOrDefault()) == true) { innerport.BeAttachTo = true; return innerport; } //else //{ // innerport.DisableAttachTo = true; // return null; //} } else { port.DataItem.ShowConnectors = true; if (port.CanAttachTo(blockDesignerItemTempLink.Items.FirstOrDefault()) == true) { port.BeAttachTo = true; return port; } //else //{ // port.DisableAttachTo = true; // return null; //} } } } return null; } public static void ClearNearPort(this IDiagramViewModel diagramViewModel) { diagramViewModel.Items.OfType().ToList().SelectMany(n => n.Connectors).Where(p => p.BeAttachTo == true || p.DisableAttachTo == true).ToList() .ForEach(p => { p.DisableAttachTo = false; p.BeAttachTo = false; }); } public static void ClearNearContain(this IDiagramViewModel diagramViewModel) { diagramViewModel.Items.OfType().ToList().SelectMany(n => n.GetAllContainers()).Where(p => p.BeAttachTo == true || p.DisableAttachTo == true).ToList() .ForEach(p => { p.DisableAttachTo = false; p.BeAttachTo = false; }); } #endregion #region Block拖拽预览-拖拽完成 public static void PreviewNearBlock(this IDiagramViewModel diagramViewModel, List blocks) { if (blocks.Any()) { diagramViewModel.ClearNearPort(); diagramViewModel.ClearNearContain(); var links = BlockDesignerItemTempLink.Build(blocks); foreach (BlockDesignerItemTempLink item in links) { var container = diagramViewModel.FindNearContainerToAttachTo(item); if (container != null) { continue; } diagramViewModel.FindNearPortToAttachTo(item, false); } } } public static void FinishNearBlock(this IDiagramViewModel diagramViewModel, List blocks) { if (blocks.Any()) { diagramViewModel.ClearNearPort(); diagramViewModel.ClearNearContain(); var links = BlockDesignerItemTempLink.Build(blocks); foreach (BlockDesignerItemTempLink item in links) { var container = diagramViewModel.FindNearContainerToAttachTo(item); if (container != null) { container.DataItem.AddChild(item.Items.FirstOrDefault(), container);//待完善 container.BeAttachTo = false; container.DisableAttachTo = false; continue; } var portTuple = diagramViewModel.FindNearPortToAttachTo(item, true); var portParent = portTuple.Item1; var portNext = portTuple.Item2; if (portParent != null) { (portParent.DataItem as BlockDesignerItemViewModel).AddNext(item.Items.FirstOrDefault()); portParent.BeAttachTo = false; portParent.DisableAttachTo = false; } else { if (item.Items.FirstOrDefault().Parent != null) { (item.Items.FirstOrDefault().Parent as BlockDesignerItemViewModel).RemoveNext(); } } if (portNext != null) { item.Items.LastOrDefault().AddNext(portNext.DataItem as BlockDesignerItemViewModel); portNext.BeAttachTo = false; portNext.DisableAttachTo = false; } else { if (item.Items.LastOrDefault().Next != null) { item.Items.LastOrDefault().RemoveNext(); } } } } } #endregion } }