DynamicGridColumnNameSelectorWindow.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. using InABox.Core;
  2. using InABox.WPF;
  3. using Syncfusion.Pdf.Parsing;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.ComponentModel;
  7. using System.Linq;
  8. using System.Runtime.CompilerServices;
  9. using System.Text;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Data;
  15. using System.Windows.Documents;
  16. using System.Windows.Input;
  17. using System.Windows.Media;
  18. using System.Windows.Media.Imaging;
  19. using System.Windows.Shapes;
  20. namespace InABox.DynamicGrid;
  21. public class DynamicGridColumnNameSelectorGrid : DynamicItemsListGrid<DynamicGridColumnNameSelectorItem>, INotifyPropertyChanged
  22. {
  23. private bool _canSave;
  24. public bool CanSave
  25. {
  26. get => _canSave;
  27. set
  28. {
  29. _canSave = value;
  30. DoPropertyChanged();
  31. }
  32. }
  33. private bool _onlyVisible;
  34. public bool OnlyVisible
  35. {
  36. get => _onlyVisible;
  37. set
  38. {
  39. _onlyVisible = value;
  40. Refresh(false, true);
  41. DoPropertyChanged();
  42. }
  43. }
  44. private List<DynamicGridColumnNameSelectorItem> _items;
  45. public string SearchText { get; set; }
  46. public DynamicGridColumnNameSelectorGrid(Type type, IEnumerable<string> columnNames)
  47. {
  48. var itemMap = new Dictionary<string, DynamicGridColumnNameSelectorItem>();
  49. var items = new List<DynamicGridColumnNameSelectorItem>();
  50. var parentCols = new Dictionary<string, List<DynamicGridColumnNameSelectorItem>>();
  51. foreach (var column in columnNames)
  52. {
  53. var item = new DynamicGridColumnNameSelectorItem();
  54. var props = column.Split('.');
  55. string? parent = null;
  56. for (int i = 0; i < props.Length - 1; ++i)
  57. {
  58. if (parent is null)
  59. {
  60. parent = props[i];
  61. }
  62. else
  63. {
  64. parent = $"{parent}.{props[i]}";
  65. }
  66. parentCols.GetValueOrAdd(parent).Add(item);
  67. }
  68. var prop = DatabaseSchema.Property(type, column);
  69. item.ColumnName = column;
  70. item.ParentColumn = parent;
  71. item.Display = props[^1];
  72. item.IsParent = false;
  73. item.Comment = prop?.Comment ?? "";
  74. item.IsVisible = (prop?.Editor.Visible ?? Visible.Optional) != Visible.Hidden;
  75. items.Add(item);
  76. }
  77. foreach (var (col, children) in parentCols)
  78. {
  79. var prop = DatabaseSchema.Property(type, col);
  80. var lastColIdx = col.LastIndexOf('.');
  81. var item = new DynamicGridColumnNameSelectorItem
  82. {
  83. ColumnName = col,
  84. IsParent = true,
  85. Comment = prop?.Comment ?? "",
  86. IsVisible = children.Any(x => x.IsVisible)
  87. };
  88. if (lastColIdx == -1)
  89. {
  90. item.ParentColumn = null;
  91. item.Display = col;
  92. }
  93. else
  94. {
  95. item.ParentColumn = col[..lastColIdx];
  96. item.Display = col[(lastColIdx + 1)..];
  97. }
  98. items.Add(item);
  99. }
  100. items.Sort((a, b) => a.ColumnName.CompareTo(b.ColumnName));
  101. _items = items;
  102. }
  103. protected override void DoReconfigure(DynamicGridOptions options)
  104. {
  105. base.DoReconfigure(options);
  106. options.Clear();
  107. options.FilterRows = true;
  108. }
  109. protected override void SelectItems(CoreRow[]? rows)
  110. {
  111. base.SelectItems(rows);
  112. CanSave = rows is not null && rows.Any(x => !LoadItem(x).IsParent);
  113. if(rows is not null)
  114. {
  115. foreach(var row in rows)
  116. {
  117. Component.ExpandRow(row);
  118. }
  119. }
  120. }
  121. protected override DynamicGridColumns LoadColumns()
  122. {
  123. var columns = new DynamicGridColumns<DynamicGridColumnNameSelectorItem>();
  124. columns.Add(x => x.Display, caption: "Name", width: 250);
  125. columns.Add(x => x.Comment);
  126. return columns;
  127. }
  128. private UIComponent? _uiComponent;
  129. private UIComponent Component
  130. {
  131. get
  132. {
  133. _uiComponent ??= new UIComponent(this);
  134. return _uiComponent;
  135. }
  136. }
  137. private class UIComponent : DynamicGridTreeUIComponent<DynamicGridColumnNameSelectorItem, string?>
  138. {
  139. DynamicGridColumnNameSelectorGrid Grid;
  140. public UIComponent(DynamicGridColumnNameSelectorGrid grid) : base(x => x.ColumnName, x => x.ParentColumn, null)
  141. {
  142. Parent = grid;
  143. Grid = grid;
  144. ExpandMode = DynamicTreeGridExpandMode.None;
  145. ShowHeader = false;
  146. MinRowHeight = 25;
  147. GridLines = DynamicTreeGridLines.Horizontal;
  148. }
  149. protected override Brush? GetCellForeground(CoreRow row, DynamicColumnBase column)
  150. {
  151. if(column is DynamicGridColumn gc && gc.ColumnName == nameof(DynamicGridColumnNameSelectorItem.Comment))
  152. {
  153. return Colors.Gray.ToBrush();
  154. }
  155. else
  156. {
  157. var item = Grid.LoadItem(row);
  158. if (item.IsParent)
  159. {
  160. return Colors.Gray.ToBrush();
  161. }
  162. else
  163. {
  164. return base.GetCellForeground(row, column);
  165. }
  166. }
  167. }
  168. protected override FontStyle? GetCellFontStyle(CoreRow row, DynamicColumnBase column)
  169. {
  170. if(column is DynamicGridColumn gc && gc.ColumnName == nameof(DynamicGridColumnNameSelectorItem.Comment))
  171. {
  172. return FontStyles.Italic;
  173. }
  174. else
  175. {
  176. var item = Grid.LoadItem(row);
  177. if (item.IsParent)
  178. {
  179. return FontStyles.Italic;
  180. }
  181. else
  182. {
  183. return base.GetCellFontStyle(row, column);
  184. }
  185. }
  186. }
  187. }
  188. protected override IDynamicGridUIComponent<DynamicGridColumnNameSelectorItem> CreateUIComponent() => Component;
  189. public event PropertyChangedEventHandler? PropertyChanged;
  190. protected void DoPropertyChanged([CallerMemberName] string propertyName = "")
  191. {
  192. PropertyChanged?.Invoke(this, new(propertyName));
  193. }
  194. protected override void Reload(Filters<DynamicGridColumnNameSelectorItem> criteria, Columns<DynamicGridColumnNameSelectorItem> columns, ref SortOrder<DynamicGridColumnNameSelectorItem>? sort, CancellationToken token, Action<CoreTable?, Exception?> action)
  195. {
  196. if (SearchText.IsNullOrWhiteSpace())
  197. {
  198. Items = _items.ToList();
  199. }
  200. else
  201. {
  202. Items = new();
  203. foreach(var item in _items)
  204. {
  205. if (!item.IsParent && item.ColumnName.Contains(SearchText, StringComparison.CurrentCultureIgnoreCase))
  206. {
  207. Items.Add(item);
  208. }
  209. }
  210. foreach(var item in _items)
  211. {
  212. if (item.IsParent && Items.Any(x => x.ColumnName.StartsWith(item.ColumnName + ".")))
  213. {
  214. Items.Add(item);
  215. }
  216. }
  217. }
  218. if (OnlyVisible)
  219. {
  220. Items.RemoveAll(x => !x.IsVisible);
  221. }
  222. base.Reload(criteria, columns, ref sort, token, action);
  223. }
  224. public static bool SelectColumnName(Type type, IEnumerable<string> columnNames, out string value, bool showVisibilityButton = false)
  225. {
  226. var grid = new DynamicGridColumnNameSelectorGrid(type, columnNames)
  227. {
  228. OnlyVisible = showVisibilityButton
  229. };
  230. grid.Refresh(true, true);
  231. var lbl = new Label
  232. {
  233. Content = "Search:",
  234. Margin = new Thickness(0, 0, 5, 5)
  235. };
  236. var search = new TextBox
  237. {
  238. Background = Colors.LightYellow.ToBrush(),
  239. Height = 25,
  240. Margin = new Thickness(0, 0, 0, 5),
  241. VerticalContentAlignment = VerticalAlignment.Center,
  242. };
  243. search.TextChanged += (o, e) =>
  244. {
  245. grid.SearchText = search.Text;
  246. grid.Refresh(false, true);
  247. };
  248. var onlyVisible = new CheckBox()
  249. {
  250. Content = "Only Visible?",
  251. VerticalAlignment = VerticalAlignment.Center,
  252. Margin = new(5, 0, 0, 5)
  253. };
  254. onlyVisible.Bind(CheckBox.IsCheckedProperty, grid, x => x.OnlyVisible);
  255. var control = new Grid();
  256. control.AddColumn(GridUnitType.Auto);
  257. control.AddColumn(GridUnitType.Star);
  258. if (showVisibilityButton)
  259. {
  260. control.AddColumn(GridUnitType.Auto);
  261. }
  262. else
  263. {
  264. control.AddColumn(0);
  265. }
  266. control.AddRow(GridUnitType.Auto);
  267. control.AddRow(GridUnitType.Star);
  268. control.AddChild(lbl, 0, 0);
  269. control.AddChild(search, 0, 1);
  270. control.AddChild(onlyVisible, 0, 2);
  271. control.AddChild(grid, 1, 0, colSpan: 3);
  272. var window = new DynamicContentDialog(control)
  273. {
  274. Title = "Select Column",
  275. Width = 600,
  276. Height = 600,
  277. WindowStartupLocation = WindowStartupLocation.CenterScreen
  278. };
  279. window.Bind(DynamicContentDialog.CanSaveProperty, grid, x => x.CanSave);
  280. grid.OnCellDoubleClick += (o, e) =>
  281. {
  282. if (e.Row is null) return;
  283. var item = grid.LoadItem(e.Row);
  284. if (!item.IsParent)
  285. {
  286. window.DialogResult = true;
  287. }
  288. };
  289. if(window.ShowDialog() == true && grid.SelectedRows.FirstOrDefault() is CoreRow row)
  290. {
  291. var item = grid.LoadItem(row);
  292. if (!item.IsParent)
  293. {
  294. value = item.ColumnName;
  295. return true;
  296. }
  297. }
  298. value = "";
  299. return false;
  300. }
  301. }
  302. public class DynamicGridColumnNameSelectorItem : BaseObject
  303. {
  304. public string ColumnName { get; set; } = "";
  305. public string Display { get; set; } = "";
  306. public string? ParentColumn { get; set; }
  307. public string Comment { get; set; } = "";
  308. public bool IsVisible { get; set; }
  309. public bool IsParent { get; set; }
  310. }