ShapesController.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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 System.Windows.Controls;
  10. using System.Collections.Generic;
  11. using System.Collections.Specialized;
  12. using Aga.Diagrams;
  13. using Aga.Diagrams.Controls;
  14. namespace FlowWorkEditDemo
  15. {
  16. class ShapesController : IDiagramController
  17. {
  18. private class UpdateScope : IDisposable
  19. {
  20. private ShapesController _parent;
  21. public bool IsInprogress { get; set; }
  22. public UpdateScope(ShapesController parent)
  23. {
  24. _parent = parent;
  25. }
  26. public void Dispose()
  27. {
  28. IsInprogress = false;
  29. _parent.UpdateView();
  30. }
  31. }
  32. private List<ShapeBase> Shapes { get; set; }
  33. private DiagramView View { get; set; }
  34. internal FlowchartModel Model { get; set; }
  35. private UpdateScope UpdateScope1 { get; set; }
  36. public ShapesController(DiagramView view, FlowchartModel model)
  37. {
  38. View = view;
  39. Model = model;
  40. Model.Nodes.CollectionChanged += NodesCollectionChanged;
  41. Model.Links.CollectionChanged += LinksCollectionChanged;
  42. UpdateScope1 = new UpdateScope(this);
  43. foreach (var t in Model.Nodes)
  44. {
  45. t.PropertyChanged += NodePropertyChanged;
  46. }
  47. UpdateView();
  48. }
  49. void LinksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  50. {
  51. UpdateView();
  52. }
  53. void NodesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  54. {
  55. if (e.NewItems != null)
  56. {
  57. foreach (var t in e.NewItems.OfType<INotifyPropertyChanged>())
  58. {
  59. t.PropertyChanged += NodePropertyChanged;
  60. }
  61. }
  62. if (e.OldItems != null)
  63. {
  64. foreach (var t in e.OldItems.OfType<INotifyPropertyChanged>())
  65. {
  66. t.PropertyChanged -= NodePropertyChanged;
  67. }
  68. }
  69. UpdateView();
  70. }
  71. void NodePropertyChanged(object sender, PropertyChangedEventArgs e)
  72. {
  73. var fn = sender as FlowNode;
  74. var n = View.Children.OfType<Node>().FirstOrDefault(p => p.ModelElement == fn);
  75. if (fn != null && n != null)
  76. UpdateNode(fn, n);
  77. }
  78. private Node UpdateNode(FlowNode node, Node item)
  79. {
  80. if (item == null)
  81. {
  82. item = new Node
  83. {
  84. ModelElement = node
  85. };
  86. CreatePorts(node, item);
  87. item.Content = CreateContent(node);
  88. }
  89. item.Width = 120;
  90. item.Height = 60;
  91. item.CanResize = false;
  92. item.SetValue(Canvas.LeftProperty, node.Column * View.GridCellSize.Width + 10);
  93. item.SetValue(Canvas.TopProperty, node.Row * View.GridCellSize.Height + 25);
  94. return item;
  95. }
  96. private void CreatePorts(FlowNode node, Node item)
  97. {
  98. foreach (var kind in node.GetPorts())
  99. {
  100. var port = new EllipsePort
  101. {
  102. Width = 10,
  103. Height = 10,
  104. Margin = new Thickness(-5),
  105. Visibility = Visibility.Visible,
  106. VerticalAlignment = ToVerticalAligment(kind),
  107. HorizontalAlignment = ToHorizontalAligment(kind),
  108. CanAcceptIncomingLinks = kind == PortKinds.Top
  109. };
  110. port.CanAcceptOutgoingLinks = !port.CanAcceptIncomingLinks;
  111. port.Tag = kind;
  112. port.Cursor = Cursors.Cross;
  113. port.CanCreateLink = true;
  114. item.Ports.Add(port);
  115. }
  116. }
  117. private static VerticalAlignment ToVerticalAligment(PortKinds kind)
  118. {
  119. var alignment = kind switch
  120. {
  121. PortKinds.Top => VerticalAlignment.Top,
  122. PortKinds.Bottom => VerticalAlignment.Bottom,
  123. _ => VerticalAlignment.Center,
  124. };
  125. return alignment;
  126. }
  127. private static HorizontalAlignment ToHorizontalAligment(PortKinds kind)
  128. {
  129. var alignment = kind switch
  130. {
  131. PortKinds.Left => HorizontalAlignment.Left,
  132. PortKinds.Right => HorizontalAlignment.Right,
  133. _ => HorizontalAlignment.Center,
  134. };
  135. return alignment;
  136. }
  137. public static FrameworkElement CreateContent(FlowNode node)
  138. {
  139. var textBlock = new TextBlock()
  140. {
  141. VerticalAlignment = VerticalAlignment.Center,
  142. HorizontalAlignment = HorizontalAlignment.Center
  143. };
  144. var b = new Binding("Text")
  145. {
  146. Source = node
  147. };
  148. textBlock.SetBinding(TextBlock.TextProperty, b);
  149. FrameworkElement ui = node.Kind switch
  150. {
  151. NodeKinds.Start or NodeKinds.End => GetStartOrEndUI(textBlock),
  152. NodeKinds.Action => GetActionUI(textBlock),
  153. _ => GetDefaultUI(textBlock),
  154. };
  155. return ui;
  156. }
  157. private static FrameworkElement GetStartOrEndUI(TextBlock textBlock)
  158. {
  159. return new Border
  160. {
  161. CornerRadius = new CornerRadius(15),
  162. BorderBrush = Brushes.Black,
  163. BorderThickness = new Thickness(1),
  164. Background = Brushes.Yellow,
  165. Child = textBlock
  166. };
  167. }
  168. private static FrameworkElement GetDefaultUI(TextBlock textBlock)
  169. {
  170. var ui = new Path
  171. {
  172. Stroke = Brushes.Black,
  173. StrokeThickness = 1,
  174. Fill = Brushes.Pink
  175. };
  176. var converter = new GeometryConverter();
  177. ui.Data = (Geometry)converter.ConvertFrom("M 0,0.25 L 0.5 0 L 1,0.25 L 0.5,0.5 Z");
  178. ui.Stretch = Stretch.Uniform;
  179. var grid = new Grid();
  180. grid.Children.Add(ui);
  181. grid.Children.Add(textBlock);
  182. return grid;
  183. }
  184. private static FrameworkElement GetActionUI(TextBlock textBlock)
  185. {
  186. var ui = new Border
  187. {
  188. BorderBrush = Brushes.Black,
  189. BorderThickness = new Thickness(1),
  190. Background = Brushes.Lime
  191. };
  192. ui.Child = textBlock;
  193. return ui;
  194. }
  195. private List<ShapeBase> CreateModel()
  196. {
  197. var list = new List<ShapeBase>();
  198. var s = new RectangleShape();
  199. s.Location = new Point(10, 10);
  200. s.Size = new Size(50, 50);
  201. list.Add(s);
  202. var s2 = new RectangleShape
  203. {
  204. Location = new Point(200, 10),
  205. Size = new Size(50, 50)
  206. };
  207. list.Add(s2);
  208. var s3 = new EllipseShape();
  209. s3.Location = new Point(90, 100);
  210. s3.Size = new Size(80, 50);
  211. list.Add(s3);
  212. s.Links.Add(s3);
  213. s3.Links.Add(s2);
  214. s2.Links.Add(s);
  215. return list;
  216. }
  217. private void UpdateView()
  218. {
  219. if (!UpdateScope1.IsInprogress)
  220. {
  221. View.Children.Clear();
  222. foreach (var node in Model.Nodes)
  223. View.Children.Add(UpdateNode(node, null));
  224. foreach (var link in Model.Links)
  225. View.Children.Add(CreateLink(link));
  226. }
  227. }
  228. private IPort FindPort(FlowNode node, PortKinds portKind)
  229. {
  230. var inode = View.Items.FirstOrDefault(p => p.ModelElement == node) as INode;
  231. if (inode == null)
  232. return null;
  233. var port = inode.Ports.OfType<FrameworkElement>().FirstOrDefault(
  234. p => p.VerticalAlignment == ToVerticalAligment(portKind)
  235. && p.HorizontalAlignment == ToHorizontalAligment(portKind)
  236. );
  237. return (IPort)port;
  238. }
  239. private Control CreateLink(Link link)
  240. {
  241. var item = new OrthogonalLink
  242. {
  243. ModelElement = link,
  244. EndCap = true,
  245. Source = FindPort(link.Source, link.SourcePort),
  246. Target = FindPort(link.Target, link.TargetPort)
  247. };
  248. var b = new Binding("Text")
  249. {
  250. Source = link
  251. };
  252. item.SetBinding(LinkBase.LabelProperty, b);
  253. return item;
  254. }
  255. private void BindEvents()
  256. {
  257. foreach (var s in Shapes)
  258. {
  259. s.PropertyChanged += ShapePropertyChanged;
  260. }
  261. }
  262. void ShapePropertyChanged(object sender, PropertyChangedEventArgs e)
  263. {
  264. var shape = sender as ShapeBase;
  265. UpdateUIElement(shape);
  266. }
  267. private void UpdateUIElement(ShapeBase shape)
  268. {
  269. UpdateUIElement(shape, (Node)View.FindItem(shape));
  270. }
  271. private void UpdateUIElement(ShapeBase shape, Node item)
  272. {
  273. if (item == null)
  274. {
  275. item = new Node();
  276. if (shape is RectangleShape)
  277. {
  278. item.Ports.Add(new RectPort() { Visibility = Visibility.Hidden });
  279. var ui = new Border();
  280. ui.CornerRadius = new CornerRadius(15);
  281. ui.BorderBrush = new SolidColorBrush(Colors.Black);
  282. ui.BorderThickness = new Thickness(1);
  283. ui.Background = new SolidColorBrush(Colors.Yellow);
  284. item.Content = ui;
  285. }
  286. else
  287. {
  288. item.Ports.Add(new EllipsePort() { Visibility = Visibility.Hidden });
  289. var ui = new Ellipse
  290. {
  291. Fill = Brushes.Green,
  292. Stroke = Brushes.Black,
  293. StrokeThickness = 1
  294. };
  295. item.Content = ui;
  296. }
  297. item.ModelElement = shape;
  298. View.Children.Add(item);
  299. }
  300. item.Width = shape.Size.Width;
  301. item.Height = shape.Size.Height;
  302. item.SetValue(Canvas.LeftProperty, shape.Location.X);
  303. item.SetValue(Canvas.TopProperty, shape.Location.Y);
  304. }
  305. private void CreateLinks(ShapeBase shape, Node item)
  306. {
  307. foreach (var dest in shape.Links)
  308. {
  309. var destItem = (Node)View.FindItem(dest);
  310. if (destItem != null)
  311. {
  312. var link = new SegmentLink
  313. {
  314. EndCap = true,
  315. Source = item.Ports.First(),
  316. Target = destItem.Ports.First()
  317. };
  318. View.Children.Add(link);
  319. }
  320. }
  321. }
  322. #region IDiagramController Members
  323. public void UpdateItemsBounds(DiagramItem[] items, Rect[] bounds)
  324. {
  325. for (int i = 0; i < items.Length; i++)
  326. {
  327. var node = items[i].ModelElement as FlowNode;
  328. if (node != null)
  329. {
  330. node.Column = (int)(bounds[i].X / View.GridCellSize.Width);
  331. node.Row = (int)(bounds[i].Y / View.GridCellSize.Height);
  332. }
  333. }
  334. }
  335. public void UpdateLink(LinkInfo initialState, ILink link)
  336. {
  337. }
  338. public bool CanExecuteCommand(ICommand command, object parameter)
  339. {
  340. return (command == ApplicationCommands.Delete && View.Selection.Count > 0);
  341. }
  342. public void ExecuteCommand(ICommand command, object parameter)
  343. {
  344. if (command == ApplicationCommands.Delete)
  345. {
  346. foreach (var e in View.Selection.Select(p => p.ModelElement))
  347. {
  348. if (e is ShapeBase)
  349. Shapes.Remove(e as ShapeBase);
  350. }
  351. UpdateView();
  352. }
  353. }
  354. #endregion
  355. }
  356. }