DynamicTreeView.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Linq.Expressions;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using InABox.Clients;
  13. using InABox.Core;
  14. using InABox.Wpf;
  15. using InABox.WPF;
  16. using Syncfusion.Data;
  17. using Syncfusion.UI.Xaml.TreeGrid;
  18. using Syncfusion.UI.Xaml.TreeGrid.Helpers;
  19. namespace InABox.DynamicGrid;
  20. // public class CoreTreeNode : INotifyPropertyChanged
  21. // {
  22. //
  23. // private CoreTreeNodes _owner;
  24. //
  25. // public ObservableCollection<CoreTreeNode> Children => _owner.GetChilden(_id);
  26. //
  27. // private Guid _id;
  28. // public Guid ID
  29. // {
  30. // get { return _id; }
  31. // set
  32. // {
  33. // _id = value;
  34. // RaisedOnPropertyChanged("ID");
  35. // }
  36. // }
  37. //
  38. // private Guid _parent;
  39. // public Guid Parent
  40. // {
  41. // get { return _parent; }
  42. // set
  43. // {
  44. // _parent = value;
  45. // RaisedOnPropertyChanged("Parent");
  46. // }
  47. // }
  48. //
  49. // private string _description;
  50. // public string Description
  51. // {
  52. // get { return _description; }
  53. // set
  54. // {
  55. // _description = value;
  56. // RaisedOnPropertyChanged("Description");
  57. // }
  58. // }
  59. //
  60. // private ImageSource? _image;
  61. // public ImageSource? Image
  62. // {
  63. // get { return _image; }
  64. // set
  65. // {
  66. // _image = value;
  67. // RaisedOnPropertyChanged("Image");
  68. // }
  69. // }
  70. //
  71. // public event PropertyChangedEventHandler? PropertyChanged;
  72. //
  73. // public void RaisedOnPropertyChanged(string propertyName)
  74. // {
  75. // PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  76. // }
  77. //
  78. // public CoreTreeNode(CoreTreeNodes owner)
  79. // {
  80. // _owner = owner;
  81. // _description = "";
  82. // }
  83. //
  84. // public CoreTreeNode(CoreTreeNodes owner, Guid id, Guid parent) : this(owner)
  85. // {
  86. // _id = id;
  87. // _parent = parent;
  88. // }
  89. // }
  90. //
  91. // public class CoreTreeNodes
  92. // {
  93. //
  94. // private List<CoreTreeNode> _nodes;
  95. // public ObservableCollection<CoreTreeNode> Nodes => new ObservableCollection<CoreTreeNode>(_nodes.Where(x => x.Parent == Guid.Empty));
  96. //
  97. // public CoreTreeNode? this[Guid id] => _nodes.FirstOrDefault(x => x.ID == id);
  98. //
  99. // public CoreTreeNodes()
  100. // {
  101. // _nodes = new List<CoreTreeNode>();
  102. // }
  103. //
  104. // public CoreTreeNode Add(Guid id, Guid parent)
  105. // {
  106. // var node = new CoreTreeNode(this, id, parent);
  107. // _nodes.Add(node);
  108. // return node;
  109. // }
  110. //
  111. // public void GetChildren(List<Guid> nodes, Guid id)
  112. // {
  113. // nodes.Add(id);
  114. // var children = GetChilden(id);
  115. // foreach (var child in children)
  116. // GetChildren(nodes, child.ID);
  117. // }
  118. //
  119. // public ObservableCollection<CoreTreeNode> GetChilden(Guid id)
  120. // {
  121. //
  122. // return new ObservableCollection<CoreTreeNode>(_nodes.Where(x => x.Parent.Equals(id) && (x.ID != id)));
  123. // }
  124. //
  125. // public void Load<T>(CoreTable table, Expression<Func<T, Guid>> id, Expression<Func<T, Guid>> parentid, Expression<Func<T, String>> description)
  126. // {
  127. // _nodes.Clear();
  128. // foreach (var row in table.Rows)
  129. // {
  130. // Guid _id = row.Get<T, Guid>(id);
  131. // Guid _parent = row.Get<T, Guid>(parentid);
  132. // String _description = row.Get<T, String>(description);
  133. // Add(_id, _parent).Description = _description;
  134. // }
  135. // }
  136. //
  137. // }
  138. public enum DynamicTreeOption
  139. {
  140. Add,
  141. Edit,
  142. Delete,
  143. ShowColumns
  144. }
  145. public delegate void OnSelectItem(CoreTreeNode node);
  146. public delegate void OnContextMenuOpening(CoreTreeNode node, ContextMenu menu);
  147. public abstract class DynamicTreeView<T> : ContentControl where T : BaseObject, new()
  148. {
  149. protected abstract Expression<Func<T, Guid>> ID { get; }
  150. protected abstract Expression<Func<T, Guid>> ParentID { get; }
  151. protected abstract Expression<Func<T, String>> Description { get; }
  152. private DynamicGridColumns MasterColumns { get; set; }
  153. public DynamicGridColumns VisibleColumns { get; protected set; }
  154. public DynamicActionColumns ActionColumns { get; }
  155. public DynamicGrid<T>.HiddenColumnsList HiddenColumns { get; }
  156. private readonly ContextMenu ColumnsMenu;
  157. public CoreTable Data { get; private set; }
  158. private ContextMenu _menu;
  159. private SfTreeGrid _tree;
  160. private DockPanel _dock;
  161. private Grid _grid;
  162. private Button _add;
  163. private Button _edit;
  164. private Button _delete;
  165. private Label _spacer;
  166. public event OnSelectItem OnSelectItem;
  167. public event OnContextMenuOpening OnContextMenuOpening;
  168. private double minRowHeight = 30D;
  169. private double maxRowHeight = 30D;
  170. public double MinRowHeight
  171. {
  172. get => minRowHeight;
  173. set
  174. {
  175. minRowHeight = value;
  176. CalculateRowHeight();
  177. }
  178. }
  179. public double MaxRowHeight
  180. {
  181. get => maxRowHeight;
  182. set
  183. {
  184. maxRowHeight = value;
  185. CalculateRowHeight();
  186. }
  187. }
  188. private bool _shownumbers = false;
  189. public bool ShowNumbers
  190. {
  191. get => _shownumbers;
  192. set
  193. {
  194. _shownumbers = value;
  195. _tree.Columns[1].Width = value ? 50 : 0;
  196. }
  197. }
  198. /*public double RowHeight
  199. {
  200. get => _tree.RowHeight;
  201. set => _tree.RowHeight = value;
  202. }*/
  203. public DynamicTreeView() : base()
  204. {
  205. Options = new FluentList<DynamicTreeOption>();
  206. Options.OnChanged += OptionsChanged;
  207. MasterColumns = new DynamicGridColumns();
  208. MasterColumns.ExtractColumns(typeof(T));
  209. ColumnsMenu = new ContextMenu();
  210. ColumnsMenu.Opened += ColumnsMenu_ContextMenuOpening;
  211. _grid = new Grid();
  212. _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1D, GridUnitType.Star) });
  213. _grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1D, GridUnitType.Star) });
  214. _grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1D, GridUnitType.Auto) });
  215. _grid.Children.Add(_tree);
  216. _dock = new DockPanel();
  217. _dock.SetValue(Grid.RowProperty, 1);
  218. _grid.Children.Add(_dock);
  219. _add = CreateButton(Wpf.Resources.add.AsBitmapImage(System.Drawing.Color.White), "", "Add Item", (o) => DoAddItem(Guid.Empty, true));
  220. _add.Margin = new Thickness(0, 2, 2, 0);
  221. _add.Visibility = Visibility.Collapsed;
  222. _add.SetValue(DockPanel.DockProperty, Dock.Left);
  223. _dock.Children.Add(_add);
  224. _edit = CreateButton(Wpf.Resources.pencil.AsBitmapImage(System.Drawing.Color.White), "", "Edit Item", EditItem);
  225. _edit.Margin = new Thickness(0, 2, 2, 0);
  226. _edit.Visibility = Visibility.Collapsed;
  227. _edit.SetValue(DockPanel.DockProperty, Dock.Left);
  228. _dock.Children.Add(_edit);
  229. _delete = CreateButton(Wpf.Resources.delete.AsBitmapImage(System.Drawing.Color.White), "", "Delete Item", DeleteItem);
  230. _delete.Margin = new Thickness(2, 2, 0, 0);
  231. _delete.Visibility = Visibility.Collapsed;
  232. _delete.SetValue(DockPanel.DockProperty, Dock.Right);
  233. _dock.Children.Add(_delete);
  234. _spacer = new Label();
  235. _spacer.SetValue(DockPanel.DockProperty, Dock.Left);
  236. _dock.Children.Add(_spacer);
  237. Content = _grid;
  238. SizeChanged += DynamicTreeView_SizeChanged;
  239. }
  240. #region Public Interface
  241. public void AddItem(CoreTreeNode? parentNode = null, bool edit = true)
  242. {
  243. var id = parentNode?.ID ?? Guid.Empty;
  244. DoAddItem(id, edit);
  245. }
  246. #endregion
  247. private void _tree_ContextMenuOpening(object sender, ContextMenuEventArgs e)
  248. {
  249. _menu.Items.Clear();
  250. if (OnContextMenuOpening is not null)
  251. {
  252. OnContextMenuOpening.Invoke((_tree.SelectedItem as CoreTreeNode)!, _menu);
  253. if(_menu.Items.Count == 0)
  254. {
  255. e.Handled = true;
  256. }
  257. }
  258. else
  259. {
  260. if (Options.Contains(DynamicTreeOption.Add))
  261. {
  262. _menu.AddItem("Add Item", null, (_tree.SelectedItem as CoreTreeNode)!.ID, (id) => DoAddItem(id, true));
  263. }
  264. }
  265. }
  266. private void DynamicTreeView_SizeChanged(object sender, SizeChangedEventArgs e)
  267. {
  268. CalculateRowHeight();
  269. }
  270. private void CalculateRowHeight()
  271. {
  272. if(Data != null && Data.Rows.Count > 0)
  273. {
  274. var contentHeight = _tree.ActualHeight - (_tree.Padding.Top + _tree.Padding.Bottom) - 2; // Two extra pixels of space
  275. var targetHeight = contentHeight / Data.Rows.Count;
  276. _tree.RowHeight = Math.Max(Math.Min(targetHeight, MaxRowHeight), MinRowHeight);
  277. }
  278. }
  279. private Button CreateButton(BitmapImage? image = null, string? text = null, string? tooltip = null, Action<Button>? action = null)
  280. {
  281. var button = new Button();
  282. button.SetValue(BorderBrushProperty, new SolidColorBrush(Colors.Gray));
  283. button.SetValue(BorderThicknessProperty, new Thickness(0.75));
  284. button.Height = 30;
  285. button.MinWidth = 30;
  286. button.Click += (o, e) => action?.Invoke(button);
  287. UpdateButton(button, image, text, tooltip);
  288. return button;
  289. }
  290. protected void UpdateButton(Button button, BitmapImage? image, string? text, string? tooltip = null)
  291. {
  292. var stackPnl = new StackPanel();
  293. stackPnl.Orientation = Orientation.Horizontal;
  294. if (image != null)
  295. {
  296. var img = new Image();
  297. img.Source = image;
  298. img.Margin = new Thickness(2);
  299. img.ToolTip = tooltip;
  300. stackPnl.Children.Add(img);
  301. }
  302. if (!string.IsNullOrEmpty(text))
  303. {
  304. var lbl = new Label();
  305. lbl.Content = text;
  306. lbl.VerticalAlignment = VerticalAlignment.Stretch;
  307. lbl.VerticalContentAlignment = VerticalAlignment.Center;
  308. lbl.Margin = new Thickness(2, 0, 5, 0);
  309. lbl.ToolTip = ToolTip;
  310. stackPnl.Children.Add(lbl);
  311. }
  312. button.Content = stackPnl;
  313. button.ToolTip = tooltip;
  314. }
  315. #region Options
  316. public FluentList<DynamicTreeOption> Options { get; private set; }
  317. public bool HasOption(DynamicTreeOption option, IEnumerable<DynamicTreeOption>? options = null) => (options ?? Options).Contains(option);
  318. private void OptionsChanged(object sender, EventArgs args)
  319. {
  320. _add.Visibility = HasOption(DynamicTreeOption.Add) ? Visibility.Visible : Visibility.Collapsed;
  321. _edit.Visibility = HasOption(DynamicTreeOption.Edit) ? Visibility.Visible : Visibility.Collapsed;
  322. _delete.Visibility = HasOption(DynamicTreeOption.Delete) ? Visibility.Visible : Visibility.Collapsed;
  323. ColumnsMenu.Visibility = HasOption(DynamicTreeOption.SelectColumns) ? Visibility.Visible : Visibility.Hidden;
  324. }
  325. #endregion
  326. #region CRUD
  327. protected virtual T DoCreateItem(Guid parent)
  328. {
  329. T result = new T();
  330. CoreUtils.SetPropertyValue(result, CoreUtils.GetFullPropertyName(ParentID, "."), parent);
  331. return result;
  332. }
  333. protected abstract T? DoLoadItem(Guid id);
  334. protected virtual bool DoEditItem(T item)
  335. {
  336. var form = new DynamicEditorForm(typeof(T));
  337. form.OnEditorValueChanged += (sender, name, value) =>
  338. {
  339. CoreUtils.SetPropertyValue(item, name, value);
  340. return new Dictionary<string, object?>();
  341. };
  342. form.Items = new T[] { item };
  343. return form.ShowDialog() == true;
  344. }
  345. protected abstract void DoSaveItem(T item);
  346. protected abstract bool DoDeleteItem(Guid id);
  347. protected virtual void DoAddItem(Guid id, bool edit)
  348. {
  349. try
  350. {
  351. T item = DoCreateItem(id);
  352. if (edit)
  353. {
  354. if (DoEditItem(item))
  355. {
  356. DoSaveItem(item);
  357. Refresh();
  358. }
  359. }
  360. else
  361. {
  362. DoSaveItem(item);
  363. Refresh();
  364. }
  365. }
  366. catch (Exception e)
  367. {
  368. MessageBox.Show(e.Message);
  369. }
  370. }
  371. private void EditItem(Button button)
  372. {
  373. var node = _tree.SelectedItem as CoreTreeNode;
  374. if (node == null)
  375. {
  376. MessageBox.Show("Please Select an item to edit!");
  377. return;
  378. }
  379. var item = DoLoadItem(node.ID);
  380. if (item != null && DoEditItem(item))
  381. {
  382. DoSaveItem(item);
  383. Refresh();
  384. }
  385. }
  386. private void DeleteItem(Button button)
  387. {
  388. var node = _tree.SelectedItem as CoreTreeNode;
  389. if (node == null)
  390. {
  391. MessageBox.Show("Please Select an item to edit!");
  392. return;
  393. }
  394. if (DoDeleteItem(node.ID))
  395. {
  396. Refresh();
  397. }
  398. }
  399. #endregion
  400. #region Header Actions
  401. private void ColumnsMenu_ContextMenuOpening(object sender, RoutedEventArgs e)
  402. {
  403. if (sender is not ContextMenu menu) return;
  404. menu.Items.Clear();
  405. menu.AddItem("Select Columns", null, SelectColumnsClick);
  406. LoadColumnsMenu(menu);
  407. }
  408. private void SelectColumnsClick()
  409. {
  410. var editor = new DynamicGridColumnsEditor(typeof(T));
  411. editor.Columns.AddRange(VisibleColumns);
  412. if (editor.ShowDialog().Equals(true))
  413. {
  414. VisibleColumns.Clear();
  415. VisibleColumns.AddRange(editor.Columns);
  416. SaveColumns(VisibleColumns);
  417. //OnSaveColumns?.Invoke(this, editor.Columns);
  418. Refresh(true, true);
  419. }
  420. }
  421. protected virtual void LoadColumnsMenu(ContextMenu menu)
  422. {
  423. }
  424. protected virtual void SaveColumns(DynamicGridColumns columns)
  425. {
  426. }
  427. #endregion
  428. #region Refresh
  429. private static bool IsSequenced => typeof(T).GetInterfaces().Any(x => x.Equals(typeof(ISequenceable)));
  430. public CoreTreeNodes Nodes { get; set; }
  431. protected abstract void Reload(Filters<T> criteria, Columns<T> columns, SortOrder<T>? sort, Action<CoreTable?, Exception?> action);
  432. private void AfterRefresh()
  433. {
  434. var nodes = new CoreTreeNodes();
  435. foreach (var row in Data.Rows)
  436. {
  437. var _id = row.Get(ID);
  438. var _parent = row.Get(ParentID);
  439. var _description = row.Get(Description);
  440. nodes.Add(_id, _parent).Description = _description;
  441. }
  442. Nodes = nodes;
  443. _tree.ItemsSource = nodes.Nodes;
  444. CalculateRowHeight();
  445. }
  446. protected virtual Filter<T>? DefineFilter()
  447. {
  448. return null;
  449. }
  450. private readonly List<DynamicColumnBase> ColumnList = new();
  451. private readonly Dictionary<string, string> _filterpredicates = new();
  452. public Columns<T> DataColumns()
  453. {
  454. var columns = new Columns<T>();
  455. columns.Add(ID).Add(ParentID).Add(Description);
  456. foreach (var column in VisibleColumns)
  457. columns.Add(column.ColumnName);
  458. foreach (var column in HiddenColumns.ColumnNames)
  459. columns.Add(new Column<T>(column));
  460. return columns;
  461. }
  462. protected virtual DynamicGridColumns LoadColumns()
  463. {
  464. var result = new DynamicGridColumns();
  465. var cols = new Columns<T>().Default(ColumnType.IncludeLinked, ColumnType.ExcludeID);
  466. result.AddRange(MasterColumns.Where(x => cols.Items.Any(c => c.Property.Equals(x.ColumnName)))
  467. .OrderBy(x => CoreUtils.GetPropertySequence(typeof(T), x.ColumnName)));
  468. return result;
  469. }
  470. private void LoadActionColumns(DynamicActionColumnPosition position)
  471. {
  472. for (var i = 0; i < ActionColumns.Count; i++)
  473. {
  474. var column = ActionColumns[i];
  475. if (column.Position == position)
  476. {
  477. var sColName = string.Format("ActionColumn{0}", i);
  478. if (column is DynamicImageColumn imgcol)
  479. {
  480. var newcol = new TreeGridImageColumn();
  481. newcol.MappingName = sColName;
  482. //newcol.Stretch = Stretch.Uniform;
  483. newcol.Width = column.Width == 0 ? _tree.RowHeight : column.Width;
  484. newcol.Padding = new Thickness(4);
  485. newcol.ImageHeight = _tree.RowHeight - 8;
  486. newcol.ImageWidth = _tree.RowHeight - 8;
  487. newcol.ColumnSizer = GridLengthUnitType.None;
  488. newcol.HeaderText = column.HeaderText;
  489. newcol.AllowSorting = false;
  490. ApplyFilterStyle(newcol, true, true);
  491. newcol.ShowToolTip = column.ToolTip != null;
  492. newcol.ShowHeaderToolTip = column.ToolTip != null;
  493. var style = new Style();
  494. style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  495. style.Setters.Add(new Setter(IsEnabledProperty, false));
  496. newcol.FilterRowCellStyle = style;
  497. var headstyle = new Style(typeof(GridHeaderCellControl));
  498. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  499. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  500. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  501. if (!string.IsNullOrWhiteSpace(column.HeaderText))
  502. {
  503. //headstyle.Setters.Add(new Setter(LayoutTransformProperty, new RotateTransform(270.0F)));
  504. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.0, 0.0, 0, 0)));
  505. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, 0, 0.75, 0.75)));
  506. if (imgcol.VerticalHeader)
  507. headstyle.Setters.Add(new Setter(TemplateProperty,
  508. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  509. }
  510. else
  511. {
  512. var image = imgcol.Image?.Invoke(null);
  513. if (image != null)
  514. {
  515. var template = new ControlTemplate(typeof(GridHeaderCellControl));
  516. var border = new FrameworkElementFactory(typeof(Border));
  517. border.SetValue(Border.BackgroundProperty, new SolidColorBrush(Colors.Gainsboro));
  518. border.SetValue(Border.PaddingProperty, new Thickness(4));
  519. border.SetValue(MarginProperty, new Thickness(0, 0, 1, 1));
  520. var img = new FrameworkElementFactory(typeof(Image));
  521. img.SetValue(Image.SourceProperty, image);
  522. border.AppendChild(img);
  523. template.VisualTree = border;
  524. headstyle.Setters.Add(new Setter(TemplateProperty, template));
  525. }
  526. }
  527. newcol.HeaderStyle = headstyle;
  528. _tree.Columns.Add(newcol);
  529. ColumnList.Add(column);
  530. }
  531. else if (column is DynamicTextColumn txtCol)
  532. {
  533. var newcol = new TreeGridTextColumn();
  534. newcol.TextWrapping = TextWrapping.NoWrap;
  535. newcol.TextAlignment = txtCol.Alignment == Alignment.NotSet
  536. ? TextAlignment.Left
  537. : txtCol.Alignment == Alignment.BottomLeft || txtCol.Alignment == Alignment.MiddleLeft ||
  538. txtCol.Alignment == Alignment.TopLeft
  539. ? TextAlignment.Left
  540. : txtCol.Alignment == Alignment.BottomCenter || txtCol.Alignment == Alignment.MiddleCenter ||
  541. txtCol.Alignment == Alignment.TopCenter
  542. ? TextAlignment.Center
  543. : TextAlignment.Right;
  544. newcol.AllowEditing = false;
  545. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  546. newcol.MappingName = sColName;
  547. newcol.Width = column.Width;
  548. newcol.ColumnSizer = TreeColumnSizer.None;
  549. newcol.HeaderText = column.HeaderText;
  550. newcol.AllowFiltering = column.Filters != null && column.Filters.Any();
  551. newcol.AllowSorting = false;
  552. newcol.ShowHeaderToolTip = column.ToolTip != null;
  553. var headstyle = new Style(typeof(TreeGridHeaderCell));
  554. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  555. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  556. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  557. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
  558. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.75)));
  559. if (txtCol.VerticalHeader)
  560. {
  561. headstyle.Setters.Add(new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Left));
  562. headstyle.Setters.Add(new Setter(TemplateProperty,
  563. Application.Current.Resources["VerticalColumnHeader"] as ControlTemplate));
  564. }
  565. newcol.HeaderStyle = headstyle;
  566. _tree.Columns.Add(newcol);
  567. ColumnList.Add(column);
  568. }
  569. else if (column is DynamicTemplateColumn tmplCol)
  570. {
  571. var newcol = new TreeGridTemplateColumn();
  572. newcol.CellTemplateSelector = new DynamicGrid<T>.TemplateColumnSelector() { DataTemplate = tmplCol.Template };
  573. newcol.AllowEditing = false;
  574. newcol.UpdateTrigger = UpdateSourceTrigger.PropertyChanged;
  575. newcol.Width = tmplCol.Width;
  576. newcol.ColumnSizer = TreeColumnSizer.None;
  577. newcol.HeaderText = column.HeaderText;
  578. newcol.AllowFiltering = false;
  579. newcol.AllowSorting = false;
  580. newcol.ShowToolTip = false;
  581. newcol.ShowHeaderToolTip = false;
  582. var headstyle = new Style(typeof(TreeGridHeaderCell));
  583. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  584. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  585. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  586. headstyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, -0.75, 0, 0.75)));
  587. headstyle.Setters.Add(new Setter(BorderThicknessProperty, new Thickness(0.75)));
  588. newcol.HeaderStyle = headstyle;
  589. _tree.Columns.Add(newcol);
  590. ColumnList.Add(column);
  591. }
  592. }
  593. }
  594. }
  595. private void ResizeColumns(double width, double height)
  596. {
  597. if (Data == null || width <= 0)
  598. return;
  599. Dispatcher.BeginInvoke(() =>
  600. {
  601. //var vc = DataGrid.GetVisualContainer();
  602. //vc.RowHeightManager.Reset();
  603. //vc.InvalidateMeasureInfo();
  604. foreach (var (index, size) in DynamicGrid<T>.CalculateColumnSizes(ColumnList, width, height, _tree.RowHeight))
  605. _tree.Columns[index].Width = Math.Max(0.0F, size);
  606. });
  607. //
  608. // var vc = DataGrid.GetVisualContainer();
  609. // vc.RowHeightManager.Reset();
  610. // vc.InvalidateMeasureInfo();
  611. // if (vc.ScrollOwner != null)
  612. // vc.ScrollOwner.HorizontalScrollBarVisibility = vc.ExtentWidth <= fAvailWidth ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Visible;
  613. }
  614. private void ReloadColumns()
  615. {
  616. VisibleColumns = LoadColumns();
  617. _tree.Columns.Suspend();
  618. ColumnList.Clear();
  619. _tree.Columns.Clear();
  620. LoadActionColumns(DynamicActionColumnPosition.Start);
  621. foreach (var column in VisibleColumns)
  622. {
  623. IProperty? prop;
  624. try
  625. {
  626. prop = DatabaseSchema.Property(typeof(T), column.ColumnName);
  627. }
  628. catch (Exception e)
  629. {
  630. Logger.Send(LogType.Error, ClientFactory.UserID,
  631. string.Format("Error constructing Column [{0}] : {1}\n{2}", column.ColumnName, e.Message, e.StackTrace));
  632. prop = null;
  633. }
  634. if (prop != null)
  635. {
  636. IDynamicGridEditorColumn? newcol = null;
  637. if (prop.Editor is IntegerEditor)
  638. newcol = new DynamicGridIntegerColumn<T>(column);
  639. else if (prop.Editor is CurrencyEditor)
  640. newcol = new DynamicGridCurrencyColumn<T>(column);
  641. else if (prop.Editor is DoubleEditor)
  642. newcol = new DynamicGridDoubleColumn<T>(column);
  643. else if (prop.Editor is DateTimeEditor)
  644. newcol = new DynamicGridDateTimeColumn<T>(column);
  645. else if (prop.Editor is DateEditor)
  646. newcol = new DynamicGridDateColumn<T>(column);
  647. else if (prop.Editor is TimeOfDayEditor)
  648. newcol = new DynamicGridTimeOfDayColumn<T>(column);
  649. else if (prop.Editor is TimestampEditor)
  650. newcol = new DynamicGridTimeStampColumn<T>(column);
  651. else if (prop.Editor is DurationEditor)
  652. newcol = new DynamicGridDurationColumn<T>(column);
  653. else if (prop.Editor is CheckBoxEditor)
  654. newcol = new DynamicGridCheckBoxColumn<T>(column);
  655. else if (prop.Editor is ColorEditor)
  656. newcol = new DynamicGridColorColumn<T>(column, column.Width, (int)_tree.RowHeight);
  657. else if (prop.Editor is PopupEditor)
  658. newcol = new DynamicGridPopupColumn<T>(column);
  659. else if (prop.Editor is CodePopupEditor)
  660. newcol = new DynamicGridCodePopupColumn<T>(column);
  661. else if (prop.Editor is EnumLookupEditor)
  662. newcol = new DynamicGridEnumLookupColumn<T>(column);
  663. else if (prop.Editor is ComboLookupEditor)
  664. newcol = new DynamicGridComboLookupColumn<T>(column);
  665. else if (prop.Editor is LookupEditor)
  666. newcol = new DynamicGridLookupColumn<T>(column);
  667. else if (prop.Editor is MemoEditor)
  668. newcol = new DynamicGridMemoColumn<T>(column);
  669. else if (prop.Editor is CodeEditor)
  670. newcol = new DynamicGridCodeColumn<T>(column);
  671. else if (prop.Editor is UniqueCodeEditor)
  672. newcol = new DynamicGridUniqueCodeColumn<T>(column);
  673. else if (prop.Editor is TextBoxEditor)
  674. newcol = new DynamicGridTextBoxColumn<T>(column);
  675. if (newcol != null)
  676. {
  677. newcol.GetEntity = () => _editingObject.Object;
  678. newcol.EntityChanged += DoEntityChanged;
  679. if (!newcol.VariableHeight)
  680. gridRowResizingOptions.ExcludeColumns.Add(newcol.MappingName);
  681. newcol.Column.AllowEditing = newcol.Editable && IsDirectEditMode();
  682. var summary = newcol.Summary();
  683. if (summary != null)
  684. Summaries.Add(summary);
  685. ApplyFilterStyle(newcol.Column, newcol.Filtered, false);
  686. var headstyle = new Style(typeof(TreeGridHeaderCell));
  687. headstyle.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.Gainsboro)));
  688. headstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  689. headstyle.Setters.Add(new Setter(FontSizeProperty, 12D));
  690. newcol.Column.HeaderStyle = headstyle;
  691. var cellstyle = new Style();
  692. if (IsDirectEditMode())
  693. {
  694. if (prop.Editor is null || !prop.Editor.Editable.IsDirectEditable())
  695. {
  696. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  697. new SolidColorBrush(Colors.WhiteSmoke)));
  698. newcol.Column.AllowEditing = false;
  699. }
  700. else
  701. {
  702. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  703. new SolidColorBrush(Colors.LightYellow)));
  704. newcol.Column.AllowEditing = true;
  705. }
  706. cellstyle.Setters.Add(new Setter(ForegroundProperty, new SolidColorBrush(Colors.Black)));
  707. newcol.Column.CellStyle = cellstyle;
  708. }
  709. else
  710. {
  711. cellstyle.Setters.Add(new Setter(BackgroundProperty,
  712. new Binding()
  713. {
  714. Path = new PropertyPath("."), Converter = CellBackgroundConverter,
  715. ConverterParameter = column.ColumnName
  716. }));
  717. cellstyle.Setters.Add(new Setter(ForegroundProperty,
  718. new Binding()
  719. { Converter = CellForegroundConverter, ConverterParameter = column.ColumnName }));
  720. cellstyle.Setters.Add(new Setter(FontSizeProperty,
  721. new Binding()
  722. { Converter = CellFontSizeConverter, ConverterParameter = column.ColumnName }));
  723. cellstyle.Setters.Add(new Setter(FontStyleProperty,
  724. new Binding()
  725. { Converter = CellFontStyleConverter, ConverterParameter = column.ColumnName }));
  726. cellstyle.Setters.Add(new Setter(FontWeightProperty,
  727. new Binding()
  728. { Converter = CellFontWeightConverter, ConverterParameter = column.ColumnName }));
  729. newcol.Column.CellStyle = cellstyle;
  730. }
  731. _tree.Columns.Add(newcol.Column);
  732. ColumnList.Add(column);
  733. foreach (var extra in newcol.ExtraColumns)
  734. AddHiddenColumn(extra);
  735. }
  736. }
  737. }
  738. LoadActionColumns(DynamicActionColumnPosition.End);
  739. _tree.Columns.Resume();
  740. _tree.RefreshColumns();
  741. foreach (var key in _filterpredicates.Keys.ToArray())
  742. if (_tree.Columns.Any(x => string.Equals(x.MappingName, key)))
  743. {
  744. var predicates = Serialization.Deserialize<List<FilterPredicate>>(_filterpredicates[key]);
  745. foreach (var predicate in predicates)
  746. {
  747. _tree.Columns[key].FilterPredicates.Add(predicate);
  748. }
  749. }
  750. else
  751. {
  752. _filterpredicates.Remove(key);
  753. }
  754. ResizeColumns(DataGrid, DataGrid.ActualWidth - 2, DataGrid.ActualHeight - 2);
  755. }
  756. public void Refresh(bool reloadColumns, bool reloadData)
  757. {
  758. _tree.ItemsSource = null;
  759. if (reloadColumns && HasOption(DynamicTreeOption.ShowColumns))
  760. ReloadColumns();
  761. if (reloadData)
  762. {
  763. var filters = new Filters<T>();
  764. filters.Add(DefineFilter());
  765. var sort = LookupFactory.DefineSort<T>();
  766. if (sort == null && IsSequenced)
  767. sort = new SortOrder<T>("Sequence");
  768. Reload(filters, DataColumns(), sort, (table, exception) =>
  769. {
  770. if(exception != null)
  771. {
  772. Dispatcher.Invoke(() =>
  773. {
  774. MessageWindow.ShowError("Sorry! We couldn't load the data.", exception);
  775. });
  776. }
  777. else if(table is not null)
  778. {
  779. Data = table;
  780. Dispatcher.Invoke(() =>
  781. {
  782. AfterRefresh();
  783. });
  784. }
  785. });
  786. }
  787. }
  788. #endregion
  789. }