Controller.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. using System;
  2. using System.Linq;
  3. using System.Windows;
  4. using System.Windows.Data;
  5. using System.Windows.Media;
  6. using System.Windows.Input;
  7. using System.ComponentModel;
  8. using System.Windows.Shapes;
  9. using SHJX.Service.WorkFlowEdit;
  10. using System.Windows.Controls;
  11. using SHJX.Service.Common.UserColor;
  12. using System.Collections.Generic;
  13. namespace Flowchart
  14. {
  15. class Controller : IDiagramController
  16. {
  17. private class UpdateScope : IDisposable
  18. {
  19. private readonly Controller _parent;
  20. public bool IsInprogress { get; set; }
  21. public UpdateScope(Controller parent)
  22. {
  23. _parent = parent;
  24. }
  25. public void Dispose()
  26. {
  27. IsInprogress = false;
  28. _parent.UpdateView();
  29. }
  30. }
  31. private readonly DiagramView _view;
  32. private readonly FlowchartModel _model;
  33. private readonly UpdateScope _updateScope;
  34. public Controller(DiagramView view, FlowchartModel model)
  35. {
  36. _view = view;
  37. _model = model;
  38. _model.Nodes.CollectionChanged += NodesCollectionChanged;
  39. _model.Links.CollectionChanged += LinksCollectionChanged;
  40. _updateScope = new UpdateScope(this);
  41. foreach (FlowNode t in _model.Nodes)
  42. {
  43. t.PropertyChanged += NodePropertyChanged;
  44. }
  45. UpdateView();
  46. }
  47. void NodesCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  48. {
  49. if (e.NewItems != null)
  50. {
  51. foreach (INotifyPropertyChanged t in e.NewItems.OfType<INotifyPropertyChanged>())
  52. {
  53. t.PropertyChanged += NodePropertyChanged;
  54. }
  55. }
  56. if (e.OldItems != null)
  57. {
  58. foreach (INotifyPropertyChanged t in e.OldItems.OfType<INotifyPropertyChanged>())
  59. {
  60. t.PropertyChanged -= NodePropertyChanged;
  61. }
  62. }
  63. UpdateView();
  64. }
  65. void LinksCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  66. {
  67. UpdateView();
  68. }
  69. void NodePropertyChanged(object sender, PropertyChangedEventArgs e)
  70. {
  71. FlowNode fn = sender as FlowNode;
  72. Node n = _view.Children.OfType<Node>().FirstOrDefault(p => p.ModelElement.Equals(fn));
  73. if (fn == null || n == null)
  74. {
  75. return;
  76. }
  77. UpdateNode(fn, n);
  78. }
  79. private void UpdateView()
  80. {
  81. if (!_updateScope.IsInprogress)
  82. {
  83. _view.Children.Clear();
  84. foreach (FlowNode node in _model.Nodes)
  85. {
  86. _view.Children.Add(UpdateNode(node, null));
  87. }
  88. foreach (Link link in _model.Links)
  89. {
  90. _view.Children.Add(CreateLink(link));
  91. }
  92. }
  93. }
  94. private Node UpdateNode(FlowNode node, Node item)
  95. {
  96. if (item == null)
  97. {
  98. item = new Node
  99. {
  100. ModelElement = node
  101. };
  102. CreatePorts(node, item);
  103. item.Content = CreateContent(node);
  104. }
  105. item.Width = 100;
  106. item.Height = 60;
  107. item.CanResize = false;
  108. item.SetValue(Canvas.LeftProperty, node.Column * _view.GridCellSize.Width + 10);
  109. item.SetValue(Canvas.TopProperty, node.Row * _view.GridCellSize.Height + 25);
  110. return item;
  111. }
  112. public static FrameworkElement CreateContent(FlowNode node)
  113. {
  114. TextBlock textBlock = new()
  115. {
  116. Foreground = Brushes.White,
  117. VerticalAlignment = VerticalAlignment.Center,
  118. HorizontalAlignment = HorizontalAlignment.Center
  119. };
  120. Binding bd = new("Text") { Source = node };
  121. textBlock.SetBinding(TextBlock.TextProperty, bd);
  122. FrameworkElement ui = node.Kind switch
  123. {
  124. NodeKinds.Start or NodeKinds.End => GetStartAndEndUI(textBlock),
  125. NodeKinds.MotorX or NodeKinds.MotorY or NodeKinds.MotorZ or NodeKinds.ManiGrab
  126. or NodeKinds.ManiLoosen or NodeKinds.MotorZGoBack => GetStepUI(textBlock),
  127. NodeKinds.Condition => GetConditionUI(textBlock),
  128. _ => throw new ArgumentException("未找到对应的节点"),
  129. };
  130. return ui;
  131. }
  132. private static FrameworkElement GetConditionUI(TextBlock textBlock)
  133. {
  134. Path ui = new()
  135. {
  136. Stroke = Brushes.Black,
  137. StrokeThickness = 1,
  138. Fill = UColor.MainColor
  139. };
  140. GeometryConverter converter = new();
  141. ui.Data = (Geometry)converter.ConvertFrom("M 0,0.25 L 0.5 0 L 1,0.25 L 0.5,0.5 Z");
  142. ui.Stretch = Stretch.Uniform;
  143. Grid grid = new();
  144. grid.Children.Add(ui);
  145. grid.Children.Add(textBlock);
  146. return grid;
  147. }
  148. private static FrameworkElement GetStepUI(TextBlock textBlock)
  149. {
  150. return new Border
  151. {
  152. BorderBrush = Brushes.Black,
  153. BorderThickness = new Thickness(1),
  154. Background = UColor.MainColor,
  155. Child = textBlock
  156. };
  157. }
  158. private static FrameworkElement GetStartAndEndUI(TextBlock textBlock)
  159. {
  160. return new Border
  161. {
  162. CornerRadius = new CornerRadius(15),
  163. BorderBrush = Brushes.Black,
  164. BorderThickness = new Thickness(1),
  165. Background = UColor.MainColor,
  166. Child = textBlock
  167. };
  168. }
  169. private void CreatePorts(FlowNode node, Node item)
  170. {
  171. foreach (PortKinds kind in node.GetPorts())
  172. {
  173. EllipsePort port = new()
  174. {
  175. Width = 10,
  176. Height = 10,
  177. Margin = new Thickness(-5),
  178. Visibility = Visibility.Visible,
  179. VerticalAlignment = ToVerticalAligment(kind),
  180. HorizontalAlignment = ToHorizontalAligment(kind),
  181. CanAcceptIncomingLinks = kind == PortKinds.Top
  182. };
  183. port.CanAcceptOutgoingLinks = !port.CanAcceptIncomingLinks;
  184. port.Tag = kind;
  185. port.Cursor = Cursors.Cross;
  186. port.CanCreateLink = true;
  187. item.Ports.Add(port);
  188. }
  189. }
  190. private Control CreateLink(Link link)
  191. {
  192. SegmentLink item = new()
  193. {
  194. EndCap = true,
  195. ModelElement = link,
  196. Source = FindPort(link.Source, link.SourcePort),
  197. Target = FindPort(link.Target, link.TargetPort)
  198. };
  199. Binding bd = new("Text")
  200. {
  201. Source = link
  202. };
  203. item.SetBinding(LinkBase.LabelProperty, bd);
  204. return item;
  205. }
  206. private IPort FindPort(FlowNode node, PortKinds portKind)
  207. {
  208. if (_view.Items.FirstOrDefault(p => p.ModelElement.Equals(node)) is not INode inode)
  209. {
  210. return null;
  211. }
  212. FrameworkElement port = inode.Ports.OfType<FrameworkElement>().FirstOrDefault(p => p.VerticalAlignment.Equals(ToVerticalAligment(portKind)) && p.HorizontalAlignment.Equals(ToHorizontalAligment(portKind)));
  213. return (IPort)port;
  214. }
  215. private VerticalAlignment ToVerticalAligment(PortKinds kind) => kind switch
  216. {
  217. PortKinds.Top => VerticalAlignment.Top,
  218. PortKinds.Bottom => VerticalAlignment.Bottom,
  219. _ => VerticalAlignment.Center,
  220. };
  221. private HorizontalAlignment ToHorizontalAligment(PortKinds kind) => kind switch
  222. {
  223. PortKinds.Left => HorizontalAlignment.Left,
  224. PortKinds.Right => HorizontalAlignment.Right,
  225. _ => HorizontalAlignment.Center
  226. };
  227. private void DeleteSelection()
  228. {
  229. using (BeginUpdate())
  230. {
  231. IEnumerable<FlowNode> nodes = _view.Selection.Select(p => p.ModelElement as FlowNode).Where(p => p != null);
  232. IEnumerable<Link> links = _view.Selection.Select(p => p.ModelElement as Link).Where(p => p != null);
  233. _model.Nodes.RemoveRange(p => nodes.Contains(p));
  234. _model.Links.RemoveRange(p => links.Contains(p));
  235. _model.Links.RemoveRange(p => nodes.Contains(p.Source) || nodes.Contains(p.Target));
  236. }
  237. }
  238. private IDisposable BeginUpdate()
  239. {
  240. _updateScope.IsInprogress = true;
  241. return _updateScope;
  242. }
  243. #region IDiagramController Members
  244. public void UpdateItemsBounds(DiagramItem[] items, Rect[] bounds)
  245. {
  246. for (int i = 0; i < items.Length; i++)
  247. {
  248. if (items[i].ModelElement is FlowNode node)
  249. {
  250. node.Column = (int)(bounds[i].X / _view.GridCellSize.Width);
  251. node.Row = (int)(bounds[i].Y / _view.GridCellSize.Height);
  252. }
  253. }
  254. }
  255. public void UpdateLink(LinkInfo initialState, ILink link)
  256. {
  257. using (BeginUpdate())
  258. {
  259. PortBase sourcePort = link.Source as PortBase;
  260. Node source = VisualHelper.FindParent<Node>(sourcePort);
  261. PortBase targetPort = link.Target as PortBase;
  262. Node target = VisualHelper.FindParent<Node>(targetPort);
  263. _model.Links.Remove((link as LinkBase).ModelElement as Link);
  264. _model.Links.Add(new Link((FlowNode)source.ModelElement, (PortKinds)sourcePort.Tag, (FlowNode)target.ModelElement, (PortKinds)targetPort.Tag));
  265. }
  266. }
  267. public void ExecuteCommand(ICommand command, object parameter)
  268. {
  269. if (command == ApplicationCommands.Delete)
  270. DeleteSelection();
  271. }
  272. public bool CanExecuteCommand(ICommand command, object parameter)
  273. {
  274. return command == ApplicationCommands.Delete;
  275. }
  276. #endregion
  277. }
  278. }