TableBase.DesignExt.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. using FastReport.Controls;
  2. using FastReport.Utils;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel;
  6. using System.Drawing;
  7. using System.Windows.Forms;
  8. namespace FastReport.Table
  9. {
  10. internal enum MouseMode
  11. {
  12. None,
  13. SelectColumn,
  14. SelectRow,
  15. SelectCell,
  16. ResizeColumn,
  17. ResizeRow
  18. }
  19. partial class TableBase
  20. {
  21. #region Private Fields
  22. private static Cursor curDownArrow = ResourceLoader.GetCursor("DownArrow.cur");
  23. private static Cursor curRightArrow = ResourceLoader.GetCursor("RightArrow.cur");
  24. private TableClipboard clipboard;
  25. private MouseMode mouseMode;
  26. private Point startSelectionPoint;
  27. #endregion Private Fields
  28. #region Public Properties
  29. /// <summary>
  30. /// This property is not relevant to this class.
  31. /// </summary>
  32. [Browsable(false)]
  33. public new BreakableComponent BreakTo
  34. {
  35. get { return base.BreakTo; }
  36. set { base.BreakTo = value; }
  37. }
  38. /// <summary>
  39. /// This property is not relevant to this class.
  40. /// </summary>
  41. [Browsable(false)]
  42. public new bool CanGrow
  43. {
  44. get { return base.CanGrow; }
  45. set { base.CanGrow = value; }
  46. }
  47. /// <summary>
  48. /// This property is not relevant to this class.
  49. /// </summary>
  50. [Browsable(false)]
  51. public new bool CanShrink
  52. {
  53. get { return base.CanShrink; }
  54. set { base.CanShrink = value; }
  55. }
  56. /// <inheritdoc/>
  57. public override float Height
  58. {
  59. get { return base.Height; }
  60. set
  61. {
  62. if (IsDesigning && !lockColumnRowChange)
  63. {
  64. foreach (TableRow r in Rows)
  65. {
  66. r.Height += (value - base.Height) / Rows.Count;
  67. }
  68. }
  69. base.Height = value;
  70. }
  71. }
  72. /// <summary>
  73. /// This property is not relevant to this class.
  74. /// </summary>
  75. [Browsable(false)]
  76. public new Hyperlink Hyperlink
  77. {
  78. get { return base.Hyperlink; }
  79. }
  80. /// <inheritdoc/>
  81. public override bool IsSelected
  82. {
  83. get
  84. {
  85. if (Report == null)
  86. return false;
  87. return Report.Designer.SelectedObjects.IndexOf(this) != -1 || IsInternalSelected;
  88. }
  89. }
  90. /// <inheritdoc/>
  91. public override float Width
  92. {
  93. get { return base.Width; }
  94. set
  95. {
  96. if (IsDesigning && !lockColumnRowChange)
  97. {
  98. foreach (TableColumn c in Columns)
  99. {
  100. c.Width += (value - base.Width) / Columns.Count;
  101. }
  102. }
  103. base.Width = value;
  104. }
  105. }
  106. #endregion Public Properties
  107. #region Internal Properties
  108. internal TableClipboard Clipboard
  109. {
  110. get
  111. {
  112. if (clipboard == null)
  113. clipboard = new TableClipboard(this);
  114. return clipboard;
  115. }
  116. }
  117. internal MouseMode MouseMode
  118. {
  119. get { return mouseMode; }
  120. set { mouseMode = value; }
  121. }
  122. #endregion Internal Properties
  123. #region Private Properties
  124. private bool IsInternalSelected
  125. {
  126. get
  127. {
  128. if (Report == null)
  129. return false;
  130. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  131. return selection.Count > 0 && (
  132. (selection[0] is TableRow && (selection[0] as TableRow).Parent == this) ||
  133. (selection[0] is TableColumn && (selection[0] as TableColumn).Parent == this) ||
  134. (selection[0] is TableCell && (selection[0] as TableCell).Parent != null && (selection[0] as TableCell).Parent.Parent == this));
  135. }
  136. }
  137. #endregion Private Properties
  138. #region Public Methods
  139. /// <inheritdoc/>
  140. public override ContextMenuBase GetContextMenu()
  141. {
  142. return new TableObjectMenu(Report.Designer);
  143. }
  144. /// <inheritdoc/>
  145. public override void HandleKeyDown(Control sender, KeyEventArgs e)
  146. {
  147. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  148. if (!IsSelected || !(selection[0] is TableCell))
  149. return;
  150. TableCell topCell = selection[0] as TableCell;
  151. int left = topCell.Address.X;
  152. int top = topCell.Address.Y;
  153. bool selectionChanged = false;
  154. switch (e.KeyCode)
  155. {
  156. case Keys.Enter:
  157. topCell.HandleKeyDown(sender, e);
  158. break;
  159. case Keys.Delete:
  160. foreach (Base c in selection)
  161. {
  162. if (c is TableCell)
  163. (c as TableCell).Text = "";
  164. }
  165. Report.Designer.SetModified(null, "Change", Name);
  166. break;
  167. case Keys.Up:
  168. top--;
  169. selectionChanged = true;
  170. break;
  171. case Keys.Down:
  172. top += topCell.RowSpan;
  173. selectionChanged = true;
  174. break;
  175. case Keys.Left:
  176. left--;
  177. selectionChanged = true;
  178. break;
  179. case Keys.Right:
  180. left += topCell.ColSpan;
  181. selectionChanged = true;
  182. break;
  183. }
  184. if (selectionChanged)
  185. {
  186. if (left < 0)
  187. left = 0;
  188. if (left >= Columns.Count)
  189. left = Columns.Count - 1;
  190. if (top < 0)
  191. top = 0;
  192. if (top >= Rows.Count)
  193. top = Rows.Count - 1;
  194. mouseMode = MouseMode.SelectCell;
  195. SetSelection(left, top, left, top);
  196. Report.Designer.SelectionChanged(null);
  197. }
  198. e.Handled = true;
  199. }
  200. /// <inheritdoc/>
  201. public override void HandleMouseDown(FRMouseEventArgs e)
  202. {
  203. if (mouseMode == MouseMode.None)
  204. {
  205. HandleMouseHover(e);
  206. if (e.handled)
  207. {
  208. e.mode = WorkspaceMode2.Move;
  209. if (IsSelected)
  210. {
  211. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  212. if (!selection.Contains(this))
  213. {
  214. selection.Clear();
  215. selection.Add(this);
  216. }
  217. }
  218. }
  219. else
  220. {
  221. if (PointInObject(new PointF(e.x, e.y)))
  222. {
  223. e.handled = true;
  224. e.mode = WorkspaceMode2.Custom;
  225. e.activeObject = this;
  226. mouseMode = MouseMode.SelectCell;
  227. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  228. if (e.button == MouseButtons.Left)
  229. {
  230. startSelectionPoint = GetAddressAtMousePoint(new PointF(e.x, e.y), true);
  231. TableCell cell = this[startSelectionPoint.X, startSelectionPoint.Y];
  232. if (e.modifierKeys == Keys.Shift)
  233. {
  234. // toggle selection
  235. if (selection.Contains(cell))
  236. {
  237. if (selection.Count > 1)
  238. selection.Remove(cell);
  239. }
  240. else
  241. selection.Add(cell);
  242. }
  243. else
  244. {
  245. selection.Clear();
  246. selection.Add(cell);
  247. }
  248. }
  249. else if (e.button == MouseButtons.Right)
  250. {
  251. Point selectionPoint = GetAddressAtMousePoint(new PointF(e.x, e.y), true);
  252. Rectangle selectionRect = GetSelectionRect();
  253. if (!selectionRect.Contains(selectionPoint))
  254. {
  255. selection.Clear();
  256. selection.Add(this[selectionPoint.X, selectionPoint.Y]);
  257. }
  258. }
  259. }
  260. }
  261. }
  262. else if (e.button == MouseButtons.Left)
  263. {
  264. startSelectionPoint = GetAddressAtMousePoint(new PointF(e.x, e.y), false);
  265. if (mouseMode == MouseMode.SelectColumn)
  266. SetSelection(startSelectionPoint.X, 0, startSelectionPoint.X, Rows.Count - 1);
  267. else if (mouseMode == MouseMode.SelectRow)
  268. SetSelection(0, startSelectionPoint.Y, Columns.Count - 1, startSelectionPoint.Y);
  269. }
  270. }
  271. /// <inheritdoc/>
  272. public override void HandleMouseHover(FRMouseEventArgs e)
  273. {
  274. if (IsSelected)
  275. {
  276. float m = 1 / Report.Designer.Zoom;
  277. if (new RectangleF(AbsLeft + 8 * m, AbsTop - 8 * m, 16 * m, 16 * m).Contains(new PointF(e.x, e.y)))
  278. {
  279. e.handled = true;
  280. e.cursor = Cursors.SizeAll;
  281. }
  282. }
  283. }
  284. /// <inheritdoc/>
  285. public override void HandleMouseMove(FRMouseEventArgs e)
  286. {
  287. base.HandleMouseMove(e);
  288. if (!e.handled && e.button == MouseButtons.None)
  289. {
  290. PointF point = new PointF(e.x, e.y);
  291. mouseMode = MouseMode.None;
  292. // don't process if mouse is over move area
  293. HandleMouseHover(e);
  294. if (e.handled)
  295. {
  296. e.handled = false;
  297. return;
  298. }
  299. // check column resize or select
  300. if (IsSelected)
  301. {
  302. float left = AbsLeft;
  303. for (int x = 0; x < Columns.Count; x++)
  304. {
  305. float width = Columns[x].Width;
  306. left += width;
  307. if (point.Y > AbsTop && point.Y < AbsBottom && point.X > left - 3 && point.X < left + 3)
  308. {
  309. // column resize
  310. PointF pt = new PointF(e.x + 3, e.y);
  311. Point pt1 = GetAddressAtMousePoint(pt, false);
  312. Point pt2 = GetAddressAtMousePoint(pt, true);
  313. // check if we are in span
  314. if (pt1 == pt2)
  315. {
  316. mouseMode = MouseMode.ResizeColumn;
  317. e.cursor = Cursors.VSplit;
  318. e.data = Columns[x];
  319. break;
  320. }
  321. }
  322. else if (point.Y > AbsTop - 8 && point.Y < AbsTop + 2 && point.X > left - width && point.X < left)
  323. {
  324. // column select
  325. mouseMode = MouseMode.SelectColumn;
  326. e.cursor = curDownArrow;
  327. e.data = Columns[x];
  328. break;
  329. }
  330. }
  331. // check row resize or select
  332. if (mouseMode == MouseMode.None)
  333. {
  334. float top = AbsTop;
  335. for (int y = 0; y < Rows.Count; y++)
  336. {
  337. float height = Rows[y].Height;
  338. top += height;
  339. if (point.X > AbsLeft && point.X < AbsRight && point.Y > top - 3 && point.Y < top + 3)
  340. {
  341. // row resize
  342. PointF pt = new PointF(e.x, e.y + 3);
  343. Point pt1 = GetAddressAtMousePoint(pt, false);
  344. Point pt2 = GetAddressAtMousePoint(pt, true);
  345. // check if we are in span
  346. if (pt1 == pt2)
  347. {
  348. mouseMode = MouseMode.ResizeRow;
  349. e.cursor = Cursors.HSplit;
  350. e.data = Rows[y];
  351. break;
  352. }
  353. }
  354. else if (point.X > AbsLeft - 8 && point.X < AbsLeft + 2 && point.Y > top - height && point.Y < top)
  355. {
  356. // row select
  357. mouseMode = MouseMode.SelectRow;
  358. e.cursor = curRightArrow;
  359. e.data = Rows[y];
  360. break;
  361. }
  362. }
  363. }
  364. }
  365. if (mouseMode != MouseMode.None)
  366. {
  367. e.handled = true;
  368. e.mode = WorkspaceMode2.Custom;
  369. }
  370. }
  371. else if (e.mode == WorkspaceMode2.Custom && e.button == MouseButtons.Left)
  372. {
  373. switch (mouseMode)
  374. {
  375. case MouseMode.SelectColumn:
  376. SetSelection(startSelectionPoint.X, 0,
  377. GetAddressAtMousePoint(new PointF(e.x, e.y), false).X, Rows.Count - 1);
  378. break;
  379. case MouseMode.SelectRow:
  380. SetSelection(0, startSelectionPoint.Y,
  381. Columns.Count - 1, GetAddressAtMousePoint(new PointF(e.x, e.y), false).Y);
  382. break;
  383. case MouseMode.SelectCell:
  384. Point pt = GetAddressAtMousePoint(new PointF(e.x, e.y), false);
  385. SetSelection(startSelectionPoint.X, startSelectionPoint.Y, pt.X, pt.Y);
  386. break;
  387. case MouseMode.ResizeColumn:
  388. TableColumn col = e.data as TableColumn;
  389. col.Width += e.delta.X;
  390. if ((e.modifierKeys & Keys.Control) != 0 && col.Index < ColumnCount - 1)
  391. {
  392. TableColumn nextCol = Columns[col.Index + 1];
  393. nextCol.Width -= e.delta.X;
  394. }
  395. if (col.Width <= 0)
  396. col.Width = 1;
  397. break;
  398. case MouseMode.ResizeRow:
  399. TableRow row = e.data as TableRow;
  400. row.Height += e.delta.Y;
  401. if ((e.modifierKeys & Keys.Control) != 0 && row.Index < RowCount - 1)
  402. {
  403. TableRow nextRow = Rows[row.Index + 1];
  404. nextRow.Height -= e.delta.Y;
  405. }
  406. if (row.Height <= 0)
  407. row.Height = 1;
  408. break;
  409. }
  410. }
  411. }
  412. /// <inheritdoc/>
  413. public override void HandleMouseUp(FRMouseEventArgs e)
  414. {
  415. base.HandleMouseUp(e);
  416. if (mouseMode == MouseMode.ResizeRow)
  417. {
  418. // update band's height
  419. if (Parent is BandBase)
  420. (Parent as BandBase).FixHeight();
  421. Report.Designer.SetModified(null, "Size", (e.data as TableRow).Name);
  422. }
  423. if (mouseMode == MouseMode.ResizeColumn)
  424. Report.Designer.SetModified(null, "Size", (e.data as TableColumn).Name);
  425. mouseMode = MouseMode.None;
  426. }
  427. /// <inheritdoc/>
  428. public override void OnAfterInsert(InsertFrom source)
  429. {
  430. CreateUniqueNames();
  431. }
  432. /// <inheritdoc/>
  433. public override void OnBeforeInsert(int flags)
  434. {
  435. Width = TableColumn.DefaultWidth * 5;
  436. Height = TableRow.DefaultHeight * 5;
  437. RowCount = 5;
  438. ColumnCount = 5;
  439. }
  440. #endregion Public Methods
  441. #region Internal Methods
  442. internal virtual ContextMenuBase GetCellContextMenu(TableCell cell)
  443. {
  444. return null;
  445. }
  446. internal virtual SmartTagBase GetCellSmartTag(TableCell cell)
  447. {
  448. return null;
  449. }
  450. internal virtual ContextMenuBase GetColumnContextMenu(TableColumn column)
  451. {
  452. return null;
  453. }
  454. internal virtual ContextMenuBase GetRowContextMenu(TableRow row)
  455. {
  456. return null;
  457. }
  458. internal Rectangle GetSelectionRect()
  459. {
  460. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  461. int minX = 1000;
  462. int minY = 1000;
  463. int maxX = 0;
  464. int maxY = 0;
  465. foreach (Base c in selection)
  466. {
  467. if (c is TableCell)
  468. {
  469. TableCell cell = c as TableCell;
  470. Point a = cell.Address;
  471. if (a.X < minX)
  472. minX = a.X;
  473. if (a.X > maxX)
  474. maxX = a.X;
  475. if (a.Y < minY)
  476. minY = a.Y;
  477. if (a.Y > maxY)
  478. maxY = a.Y;
  479. }
  480. }
  481. return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
  482. }
  483. internal virtual void HandleCellDoubleClick(TableCell cell)
  484. {
  485. // do nothing
  486. }
  487. internal virtual string GetCellDisplayText(TableCell cell, string defaultText)
  488. {
  489. return defaultText;
  490. }
  491. internal virtual void ProvideCustomItems(TableCell cell, DataTreeView tree)
  492. {
  493. // does nothing
  494. }
  495. #endregion Internal Methods
  496. #region Private Methods
  497. private void DrawDesign(FRPaintEventArgs e)
  498. {
  499. if (IsDesigning && IsSelected)
  500. {
  501. float m = Report.Designer.DpiMultiplier();
  502. e.Graphics.DrawImage(Report.Designer.GetImage(75), (int)(AbsLeft * e.ScaleX + 8 * m), (int)(AbsTop * e.ScaleY - 8 * m));
  503. }
  504. }
  505. private void DrawDesign_Borders(FRPaintEventArgs e)
  506. {
  507. if (IsDesigning)
  508. DrawCells(e, DrawDesignBorders);
  509. }
  510. private void DrawDesign_BordersRtl(FRPaintEventArgs e)
  511. {
  512. if (IsDesigning)
  513. DrawCellsRtl(e, DrawDesignBorders);
  514. }
  515. private void DrawDesign_SelectedCells(FRPaintEventArgs e)
  516. {
  517. if (IsDesigning && IsSelected)
  518. {
  519. DrawCells(e, DrawSelectedCells);
  520. DrawSelectedRowsColumns(e);
  521. }
  522. }
  523. private void DrawDesign_SelectedCellsRtl(FRPaintEventArgs e)
  524. {
  525. if (IsDesigning && IsSelected)
  526. {
  527. DrawCellsRtl(e, DrawSelectedCells);
  528. DrawSelectedRowsColumns(e);
  529. }
  530. }
  531. private void DrawDesignBorders(FRPaintEventArgs e, TableCell cell)
  532. {
  533. if (cell.Fill is SolidFill && (cell.Fill.IsTransparent ||
  534. (cell.Fill as SolidFill).Color == Color.White))
  535. {
  536. cell.DrawMarkers(e, MarkerStyle.Rectangle);
  537. }
  538. }
  539. private void DrawSelectedCells(FRPaintEventArgs e, TableCell cell)
  540. {
  541. if (Report.Designer.SelectedObjects.Contains(cell))
  542. {
  543. Brush brush = e.Cache.GetBrush(Color.FromArgb(128, SystemColors.Highlight));
  544. e.Graphics.FillRectangle(brush, cell.AbsLeft * e.ScaleX, cell.AbsTop * e.ScaleY,
  545. cell.Width * e.ScaleX, cell.Height * e.ScaleY);
  546. }
  547. }
  548. private void DrawSelectedRowsColumns(FRPaintEventArgs e)
  549. {
  550. IGraphics g = e.Graphics;
  551. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  552. Brush brush = e.Cache.GetBrush(Color.FromArgb(128, SystemColors.Highlight));
  553. foreach (Base c in selection)
  554. {
  555. if (c is TableRow)
  556. {
  557. TableRow row = c as TableRow;
  558. g.FillRectangle(brush, AbsLeft * e.ScaleX, (row.Top + AbsTop) * e.ScaleY,
  559. Width * e.ScaleX, row.Height * e.ScaleY);
  560. }
  561. else if (c is TableColumn)
  562. {
  563. TableColumn col = c as TableColumn;
  564. g.FillRectangle(brush, (col.Left + AbsLeft) * e.ScaleX, AbsTop * e.ScaleY,
  565. col.Width * e.ScaleX, Height * e.ScaleY);
  566. }
  567. }
  568. }
  569. private Point GetAddressAtMousePoint(PointF pt, bool checkSpan)
  570. {
  571. Point result = new Point();
  572. float left = AbsLeft;
  573. for (int x = 0; x < Columns.Count; x++)
  574. {
  575. float width = Columns[x].Width;
  576. if (pt.X >= left && pt.X < left + width)
  577. {
  578. result.X = x;
  579. break;
  580. }
  581. left += width;
  582. }
  583. if (pt.X >= AbsRight)
  584. result.X = Columns.Count - 1;
  585. float top = AbsTop;
  586. for (int y = 0; y < Rows.Count; y++)
  587. {
  588. float height = Rows[y].Height;
  589. if (pt.Y >= top && pt.Y < top + height)
  590. {
  591. result.Y = y;
  592. break;
  593. }
  594. top += height;
  595. }
  596. if (pt.Y >= AbsBottom)
  597. result.Y = Rows.Count - 1;
  598. if (checkSpan)
  599. {
  600. List<Rectangle> spans = GetSpanList();
  601. foreach (Rectangle span in spans)
  602. {
  603. if (span.Contains(result))
  604. {
  605. result = span.Location;
  606. break;
  607. }
  608. }
  609. }
  610. return result;
  611. }
  612. private void SetSelection(int x1, int y1, int x2, int y2)
  613. {
  614. Rectangle rect = new Rectangle();
  615. rect.X = x1 < x2 ? x1 : x2;
  616. rect.Y = y1 < y2 ? y1 : y2;
  617. rect.Width = (int)Math.Abs(x1 - x2) + 1;
  618. rect.Height = (int)Math.Abs(y1 - y2) + 1;
  619. SelectedObjectCollection selection = Report.Designer.SelectedObjects;
  620. selection.Clear();
  621. if (mouseMode == MouseMode.SelectRow)
  622. {
  623. for (int y = rect.Top; y < rect.Bottom; y++)
  624. {
  625. selection.Add(Rows[y]);
  626. }
  627. }
  628. else if (mouseMode == MouseMode.SelectColumn)
  629. {
  630. for (int x = rect.Left; x < rect.Right; x++)
  631. {
  632. selection.Add(Columns[x]);
  633. }
  634. }
  635. else if (mouseMode == MouseMode.SelectCell)
  636. {
  637. List<Rectangle> spans = GetSpanList();
  638. // widen selection if spans are inside
  639. foreach (Rectangle span in spans)
  640. {
  641. if (rect.IntersectsWith(span))
  642. {
  643. if (span.X < rect.X)
  644. {
  645. rect.Width += rect.X - span.X;
  646. rect.X = span.X;
  647. }
  648. if (span.Right > rect.Right)
  649. rect.Width += span.Right - rect.Right;
  650. if (span.Y < rect.Y)
  651. {
  652. rect.Height += rect.Y - span.Y;
  653. rect.Y = span.Y;
  654. }
  655. if (span.Bottom > rect.Bottom)
  656. rect.Height += span.Bottom - rect.Bottom;
  657. }
  658. }
  659. for (int x = rect.Left; x < rect.Right; x++)
  660. {
  661. for (int y = rect.Top; y < rect.Bottom; y++)
  662. {
  663. selection.Add(this[x, y]);
  664. }
  665. }
  666. }
  667. }
  668. #endregion Private Methods
  669. }
  670. }