DynamicEditorGrid.xaml.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Linq;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Media;
  8. using InABox.Clients;
  9. using InABox.Core;
  10. using InABox.WPF;
  11. namespace InABox.DynamicGrid
  12. {
  13. public delegate void OnUpdateOtherEditorHandler(string columnname, object value);
  14. public delegate Dictionary<string, object?> EditorValueChangedHandler(object sender, string name, object value);
  15. /// <summary>
  16. /// Interaction logic for DynamicEditorGrid.xaml
  17. /// </summary>
  18. public partial class DynamicEditorGrid : UserControl
  19. {
  20. public delegate void EditorCreatedHandler(object sender, double height, double width);
  21. public delegate Document? FindDocumentEvent(string FileName);
  22. public delegate Document? GetDocumentEvent(Guid id);
  23. public delegate object? GetPropertyValueHandler(object sender, string name);
  24. public delegate void SaveDocumentEvent(Document document);
  25. public delegate void SetPropertyValueHandler(object sender, string name, object value);
  26. public delegate object?[] GetItemsEvent();
  27. // Column Definitions as defined by calling model
  28. private DynamicGridColumns _columns = new();
  29. private Type? LayoutType;
  30. private DynamicEditorGridLayout? Layout;
  31. public DynamicEditorGrid()
  32. {
  33. InitializeComponent();
  34. Loaded += DynamicEditorGrid_Loaded;
  35. }
  36. public DynamicEditorPages Pages { get; private set; } = new();
  37. public bool PreloadPages { get; set; }
  38. public Type UnderlyingType { get; set; }
  39. public OnLoadPage? OnLoadPage { get; set; }
  40. public OnSelectPage? OnSelectPage { get; set; }
  41. public OnUnloadPage? OnUnloadPage { get; set; }
  42. public DynamicGridColumns Columns => _columns;
  43. public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
  44. {
  45. foreach (var page in Pages)
  46. {
  47. if (page is DynamicEditPage editPage)
  48. {
  49. if (editPage.TryFindEditor(columnname, out editor))
  50. return true;
  51. }
  52. }
  53. editor = null;
  54. return false;
  55. }
  56. public IDynamicEditorControl? FindEditor(string columnname)
  57. {
  58. TryFindEditor(columnname, out var editor);
  59. return editor;
  60. }
  61. public virtual void ReconfigureEditors()
  62. {
  63. OnReconfigureEditors?.Invoke(this);
  64. }
  65. public object? GetPropertyValue(string columnname)
  66. {
  67. return OnGetPropertyValue?.Invoke(this, columnname);
  68. }
  69. public event EditorCreatedHandler? OnEditorCreated;
  70. public event OnCustomiseColumns? OnCustomiseColumns;
  71. public event OnGetEditor? OnGetEditor;
  72. public event OnGridCustomiseEditor? OnGridCustomiseEditor;
  73. public event OnGetEditorSequence? OnGetSequence;
  74. public event GetPropertyValueHandler? OnGetPropertyValue;
  75. public event SetPropertyValueHandler? OnSetPropertyValue;
  76. public event EditorValueChangedHandler? OnEditorValueChanged;
  77. public event OnAfterEditorValueChanged? OnAfterEditorValueChanged;
  78. public event OnReconfigureEditors? OnReconfigureEditors;
  79. public event OnDefineFilter? OnDefineFilter;
  80. public event OnDefineLookup? OnDefineLookups;
  81. public event OnLookupsDefined? OnLookupsDefined;
  82. public event GetDocumentEvent? OnGetDocument;
  83. public event FindDocumentEvent? OnFindDocument;
  84. public event SaveDocumentEvent? OnSaveDocument;
  85. public event GetItemsEvent? GetItems;
  86. private void DynamicEditorGrid_Loaded(object sender, RoutedEventArgs e)
  87. {
  88. //Reload();
  89. }
  90. public void Reload()
  91. {
  92. LoadPages();
  93. ReconfigureEditors();
  94. }
  95. #region Edit Page
  96. public class DynamicEditPage : ContentControl, IDynamicEditorPage
  97. {
  98. private Grid Grid;
  99. public DynamicEditorGrid EditorGrid { get; set; } = null!; // Set by DynamicEditorGrid
  100. public bool Ready { get; set; }
  101. private List<BaseDynamicEditorControl> Editors { get; set; }
  102. public PageType PageType => PageType.Editor;
  103. public int PageOrder { get; set; }
  104. public string Header { get; set; }
  105. private double GeneralHeight = 30;
  106. public DynamicEditPage(string header)
  107. {
  108. Header = header;
  109. Editors = new List<BaseDynamicEditorControl>();
  110. InitialiseContent();
  111. }
  112. public void AddEditor(string columnName, BaseEditor editor)
  113. {
  114. BaseDynamicEditorControl? element = null;
  115. element = editor switch
  116. {
  117. TextBoxEditor => new TextBoxEditorControl(),
  118. Core.RichTextEditor => new RichTextEditorControl(),
  119. URLEditor => new URLEditorControl(),
  120. CodeEditor or UniqueCodeEditor => new CodeEditorControl(),
  121. CheckBoxEditor => new CheckBoxEditorControl(),
  122. DateTimeEditor => new DateTimeEditorControl(),
  123. DateEditor dateEditor => new DateEditorControl { TodayVisible = dateEditor.TodayVisible },
  124. TimeOfDayEditor => new TimeOfDayEditorControl { NowButtonVisible = false },
  125. DurationEditor => new DurationEditorControl(),
  126. NotesEditor => new NotesEditorControl(),
  127. PINEditor => new PINEditorControl(),
  128. CheckListEditor => new CheckListBoxEditorControl(),
  129. MemoEditor => new MemoEditorControl(),
  130. JsonEditor => new JsonEditorControl(),
  131. LookupEditor => ClientFactory.IsSupported(((LookupEditor)editor).Type) ? new LookupEditorControl() : null,
  132. PopupEditor => ClientFactory.IsSupported(((PopupEditor)editor).Type) ? new PopupEditorControl() : null,
  133. CodePopupEditor => ClientFactory.IsSupported(((CodePopupEditor)editor).Type) ? new CodePopupEditorControl() : null,
  134. EnumLookupEditor or ComboLookupEditor => new LookupEditorControl(),
  135. ComboMultiLookupEditor => new MultiLookupEditorControl(),
  136. EmbeddedImageEditor imageEditor => new EmbeddedImageEditorControl
  137. {
  138. MaximumHeight = imageEditor.MaximumHeight,
  139. MaximumWidth = imageEditor.MaximumWidth,
  140. MaximumFileSize = imageEditor.MaximumFileSize
  141. },
  142. FileNameEditor fileNameEditor => new FileNameEditorControl
  143. {
  144. Filter = fileNameEditor.FileMask,
  145. AllowView = fileNameEditor.AllowView,
  146. RequireExisting = fileNameEditor.RequireExisting
  147. },
  148. FolderEditor folderEditor => new FolderEditorControl
  149. {
  150. InitialFolder = folderEditor.InitialFolder
  151. },
  152. MiscellaneousDocumentEditor => new DocumentEditorControl(),
  153. ImageDocumentEditor => new DocumentEditorControl(),
  154. VectorDocumentEditor => new DocumentEditorControl(),
  155. PDFDocumentEditor => new DocumentEditorControl(),
  156. PasswordEditor => new PasswordEditorControl(),
  157. CurrencyEditor => new CurrencyEditorControl(),
  158. DoubleEditor => new DoubleEditorControl(),
  159. IntegerEditor => new IntegerEditorControl(),
  160. Core.ScriptEditor scriptEditor => new ScriptEditorControl
  161. {
  162. SyntaxLanguage = scriptEditor.SyntaxLanguage
  163. },
  164. TimestampEditor => new TimestampEditorControl(),
  165. ColorEditor => new ColorEditorControl(),
  166. FilterEditor filter => new FilterEditorControl { FilterType = filter.Type! },
  167. ExpressionEditor expression => new ExpressionEditorControl(expression),
  168. _ => null,
  169. };
  170. if (element != null)
  171. {
  172. element.EditorDefinition = editor;
  173. element.IsEnabled = editor.Editable == Editable.Enabled;
  174. if (!string.IsNullOrWhiteSpace(editor.ToolTip))
  175. {
  176. element.ToolTip = new ToolTip() { Content = editor.ToolTip };
  177. }
  178. var label = new Label();
  179. label.Content = CoreUtils.Neatify(editor.Caption); // 2
  180. label.Margin = new Thickness(0F, 0F, 0F, 0F);
  181. label.HorizontalAlignment = HorizontalAlignment.Stretch;
  182. label.VerticalAlignment = VerticalAlignment.Stretch;
  183. label.HorizontalContentAlignment = HorizontalAlignment.Left;
  184. label.VerticalContentAlignment = VerticalAlignment.Center;
  185. label.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count);
  186. label.SetValue(Grid.ColumnProperty, 0);
  187. label.Visibility = string.IsNullOrWhiteSpace(editor.Caption) ? Visibility.Collapsed : Visibility.Visible;
  188. Grid.Children.Add(label);
  189. element.ColumnName = columnName;
  190. element.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow;
  191. Editors.Add(element);
  192. element.Margin = new Thickness(5F, 2.5F, 5F, 2.5F);
  193. double iHeight = element.DesiredHeight();
  194. if (iHeight == int.MaxValue)
  195. {
  196. Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
  197. GeneralHeight += element.MinHeight + 5.0F;
  198. }
  199. else
  200. {
  201. Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) });
  202. GeneralHeight += iHeight + 5.0F;
  203. }
  204. double iWidth = element.DesiredWidth();
  205. if (iWidth == int.MaxValue)
  206. {
  207. element.HorizontalAlignment = HorizontalAlignment.Stretch;
  208. }
  209. else
  210. {
  211. element.HorizontalAlignment = HorizontalAlignment.Left;
  212. element.Width = iWidth;
  213. }
  214. element.SetValue(Grid.RowProperty, Grid.RowDefinitions.Count - 1);
  215. element.SetValue(Grid.ColumnProperty, 1);
  216. Grid.Children.Add(element);
  217. }
  218. }
  219. [MemberNotNull(nameof(Grid))]
  220. private void InitialiseContent()
  221. {
  222. Grid = new Grid
  223. {
  224. HorizontalAlignment = HorizontalAlignment.Stretch,
  225. VerticalAlignment = VerticalAlignment.Stretch,
  226. Margin = new Thickness(0, 2.5, 0, 2.5)
  227. };
  228. Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
  229. Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  230. var scroll = new ScrollViewer
  231. {
  232. HorizontalAlignment = HorizontalAlignment.Stretch,
  233. VerticalAlignment = VerticalAlignment.Stretch,
  234. VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
  235. Padding = new Thickness(2),
  236. Content = Grid
  237. };
  238. var border = new Border
  239. {
  240. BorderBrush = new SolidColorBrush(Colors.Gray),
  241. Background = new SolidColorBrush(Colors.White),
  242. BorderThickness = new Thickness(0.75),
  243. Child = scroll
  244. };
  245. Content = border;
  246. }
  247. public void AfterSave(object item)
  248. {
  249. }
  250. public void BeforeSave(object item)
  251. {
  252. }
  253. public string Caption() => Header;
  254. public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
  255. {
  256. editor = Editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  257. return editor is not null;
  258. }
  259. public IEnumerable<BaseDynamicEditorControl> FindEditors(DynamicGridColumn column)
  260. {
  261. return Editors.Where(x => string.Equals(x.ColumnName, column.ColumnName));
  262. }
  263. #region Configure Editors
  264. private void LoadLookupColumns(string column, Dictionary<string, string> othercolumns)
  265. {
  266. othercolumns.Clear();
  267. var comps = column.Split('.').ToList();
  268. comps.RemoveAt(comps.Count - 1);
  269. var prefix = string.Format("{0}.", string.Join(".", comps));
  270. var cols = EditorGrid.Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix));
  271. foreach (var col in cols)
  272. othercolumns[col.ColumnName.Replace(prefix, "")] = col.ColumnName;
  273. }
  274. private string GetCodeColumn(string column)
  275. {
  276. var comps = column.Split('.').ToList();
  277. comps.RemoveAt(comps.Count - 1);
  278. var prefix = string.Format("{0}.", string.Join(".", comps));
  279. var cols = EditorGrid.Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix));
  280. foreach (var col in cols)
  281. {
  282. var editor = EditorGrid.OnGetEditor?.Invoke(col);
  283. if (editor is CodeEditor || editor is UniqueCodeEditor)
  284. return col.ColumnName.Split('.').Last();
  285. }
  286. return "";
  287. }
  288. private void ConfigureExpressionEditor(ExpressionEditorControl control)
  289. {
  290. control.GetItems += () => EditorGrid.GetItems?.Invoke() ?? Array.Empty<object?>();
  291. }
  292. private void ConfigurePopupEditor(PopupEditorControl popup, string column, PopupEditor editor)
  293. {
  294. popup.ColumnName = column;
  295. LoadLookupColumns(column, popup.OtherColumns);
  296. if (popup.EditorDefinition is DataLookupEditor dataLookup)
  297. LoadLookupColumns(column, dataLookup.OtherColumns);
  298. popup.OnDefineFilter += (sender, type) => { return EditorGrid.OnDefineFilter?.Invoke(sender, type); };
  299. popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  300. }
  301. private void ConfigureCodePopupEditor(CodePopupEditorControl popup, string column, CodePopupEditor editor)
  302. {
  303. popup.ColumnName = column;
  304. LoadLookupColumns(column, popup.OtherColumns);
  305. if (popup.EditorDefinition is DataLookupEditor dataLookup)
  306. LoadLookupColumns(column, dataLookup.OtherColumns);
  307. popup.CodeColumn = !string.IsNullOrEmpty(editor.CodeColumn) ? editor.CodeColumn : GetCodeColumn(column);
  308. popup.OnDefineFilter += (sender, type) => { return EditorGrid.OnDefineFilter?.Invoke(sender, type); };
  309. popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  310. }
  311. private void ConfigureLookupEditor(LookupEditorControl lookup, string column, LookupEditor editor)
  312. {
  313. if (editor.LookupWidth != int.MaxValue)
  314. lookup.Width = editor.LookupWidth;
  315. lookup.ColumnName = column;
  316. LoadLookupColumns(column, lookup.OtherColumns);
  317. if (lookup.EditorDefinition is DataLookupEditor dataLookup)
  318. LoadLookupColumns(column, dataLookup.OtherColumns);
  319. lookup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  320. lookup.OnDefineLookups += sender => { EditorGrid.OnDefineLookups?.Invoke(sender); };
  321. lookup.OnLookupsDefined += sender => { EditorGrid.OnLookupsDefined?.Invoke(sender); };
  322. }
  323. private void ConfigureEnumEditor(LookupEditorControl lookup, string column, EnumLookupEditor editor)
  324. {
  325. if (editor.LookupWidth != int.MaxValue)
  326. lookup.Width = editor.LookupWidth;
  327. lookup.ColumnName = column;
  328. lookup.OnDefineLookups += sender => { EditorGrid.OnDefineLookups?.Invoke(sender); };
  329. lookup.OnLookupsDefined += sender =>
  330. {
  331. //OnLookupsDefined?.Invoke(sender);
  332. };
  333. }
  334. private void ConfigureComboEditor(LookupEditorControl lookup, string column, ComboLookupEditor editor)
  335. {
  336. if (editor.LookupWidth != int.MaxValue)
  337. lookup.Width = editor.LookupWidth;
  338. lookup.ColumnName = column;
  339. lookup.OnDefineLookups += sender => { EditorGrid.OnDefineLookups?.Invoke(sender); };
  340. lookup.OnLookupsDefined += sender => { EditorGrid.OnLookupsDefined?.Invoke(sender); };
  341. }
  342. private void ConfigureMultiLookupEditor(MultiLookupEditorControl lookup, string column, ComboMultiLookupEditor editor)
  343. {
  344. if (editor.LookupWidth != int.MaxValue)
  345. lookup.Width = editor.LookupWidth;
  346. lookup.ColumnName = column;
  347. lookup.OnDefineLookups += sender => { EditorGrid.OnDefineLookups?.Invoke(sender); };
  348. lookup.OnLookupsDefined += sender => { EditorGrid.OnLookupsDefined?.Invoke(sender); };
  349. }
  350. private void ConfigureCheckListEditor(CheckListBoxEditorControl checks, string column, CheckListEditor editor)
  351. {
  352. checks.Width = editor.LookupWidth;
  353. checks.ColumnName = column;
  354. checks.OnDefineLookups += sender => { EditorGrid.OnDefineLookups?.Invoke(sender); };
  355. checks.OnLookupsDefined += sender => { EditorGrid.OnLookupsDefined?.Invoke(sender); };
  356. }
  357. private void ConfigureDocumentEditor(DocumentEditorControl document, string column, BaseDocumentEditor editor)
  358. {
  359. document.ColumnName = column;
  360. LoadLookupColumns(column, document.OtherColumns);
  361. if (document.EditorDefinition is DataLookupEditor dataLookup)
  362. LoadLookupColumns(column, dataLookup.OtherColumns);
  363. document.OnGetDocument += id => { return EditorGrid.OnGetDocument?.Invoke(id); };
  364. document.OnSaveDocument += doc => { EditorGrid.OnSaveDocument?.Invoke(doc); };
  365. document.OnFindDocument += file => { return EditorGrid.OnFindDocument?.Invoke(file); };
  366. document.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  367. document.Filter = editor.FileMask;
  368. }
  369. private void Lookup_OnUpdateOtherEditor(string columnname, object value)
  370. {
  371. var editor = Editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  372. if (editor != null)
  373. CoreUtils.SetPropertyValue(editor, "Value", value);
  374. }
  375. private void ConfigurePasswordEditor(PasswordEditorControl passwordEditorControl, PasswordEditor passwordEditor)
  376. {
  377. passwordEditorControl.ViewButtonVisible = passwordEditor.ViewButtonVisible;
  378. }
  379. private void ConfigureEditors()
  380. {
  381. foreach (var Editor in Editors)
  382. {
  383. var editor = Editor.EditorDefinition;
  384. var column = Editor.ColumnName;
  385. if (Editor is LookupEditorControl lookupControl)
  386. {
  387. if (editor is LookupEditor lookupEditor)
  388. ConfigureLookupEditor(lookupControl, column, lookupEditor);
  389. else if (editor is EnumLookupEditor enumEditor)
  390. ConfigureEnumEditor(lookupControl, column, enumEditor);
  391. else if (editor is ComboLookupEditor comboEditor)
  392. ConfigureComboEditor(lookupControl, column, comboEditor);
  393. }
  394. else if (Editor is MultiLookupEditorControl multiLookupEditor && editor is ComboMultiLookupEditor comboMultiLookup)
  395. {
  396. ConfigureMultiLookupEditor(multiLookupEditor, column, comboMultiLookup);
  397. }
  398. else if (Editor is CheckListBoxEditorControl checkBoxControl && editor is CheckListEditor checkListEditor)
  399. {
  400. ConfigureCheckListEditor(checkBoxControl, column, checkListEditor);
  401. }
  402. else if (Editor is PopupEditorControl popupControl && editor is PopupEditor popupEditor)
  403. {
  404. ConfigurePopupEditor(popupControl, column, popupEditor);
  405. }
  406. else if (Editor is CodePopupEditorControl codePopupControl && editor is CodePopupEditor codePopupEditor)
  407. {
  408. ConfigureCodePopupEditor(codePopupControl, column, codePopupEditor);
  409. }
  410. else if (Editor is DocumentEditorControl documentEditorControl && editor is BaseDocumentEditor baseDocumentEditor)
  411. {
  412. ConfigureDocumentEditor(documentEditorControl, column, baseDocumentEditor);
  413. }
  414. else if (Editor is PasswordEditorControl passwordEditorControl && editor is PasswordEditor passwordEditor)
  415. {
  416. ConfigurePasswordEditor(passwordEditorControl, passwordEditor);
  417. }
  418. else if (Editor is ExpressionEditorControl expressionEditorControl && editor is ExpressionEditor expressionEditor)
  419. {
  420. ConfigureExpressionEditor(expressionEditorControl);
  421. }
  422. Editor.Configure();
  423. if (!Editors.Any(x => x.ColumnName.Equals(Editor.ColumnName)))
  424. Editors.Add(Editor);
  425. Editor.Loaded = true;
  426. }
  427. }
  428. #endregion
  429. private void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object> values)
  430. {
  431. //Logger.Send(LogType.Information, "", string.Format("DynamicEditorGrid.EditorValueChanged({0})", values.Keys.Count));
  432. var changededitors = new Dictionary<string, object?>();
  433. void ExtractChanged(Dictionary<String, object?>? columns)
  434. {
  435. if (columns != null)
  436. foreach (var (change, value) in columns)
  437. if (Editors.Any(x => x.ColumnName.Equals(change)) && !changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
  438. changededitors[change] = value;
  439. }
  440. foreach (var key in values.Keys)
  441. {
  442. var changedcolumns = EditorGrid.OnEditorValueChanged?.Invoke(EditorGrid, key, values[key]);
  443. ExtractChanged(changedcolumns);
  444. }
  445. var afterchanged = EditorGrid.OnAfterEditorValueChanged?.Invoke(EditorGrid, sender.ColumnName);
  446. ExtractChanged(afterchanged);
  447. if (changededitors.Any())
  448. LoadEditorValues(changededitors);
  449. EditorGrid.ReconfigureEditors();
  450. }
  451. private void LoadEditorValues(Dictionary<string, object?>? changededitors = null)
  452. {
  453. var columnnames = changededitors != null ? changededitors.Keys.ToArray() : Editors.Select(x => x.ColumnName).ToArray();
  454. foreach (var columnname in columnnames)
  455. {
  456. var editor = Editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  457. if (editor == null)
  458. continue;
  459. var bLoaded = editor.Loaded;
  460. editor.Loaded = false;
  461. if (changededitors != null && changededitors.ContainsKey(columnname))
  462. {
  463. CoreUtils.SetPropertyValue(editor, "Value", changededitors[columnname]);
  464. }
  465. else
  466. {
  467. var curvalue = EditorGrid.GetPropertyValue(columnname);
  468. try
  469. {
  470. CoreUtils.SetPropertyValue(editor, "Value", curvalue);
  471. }
  472. catch (Exception e)
  473. {
  474. MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}");
  475. }
  476. CoreUtils.SetPropertyValue(editor, "Changed", false);
  477. }
  478. editor.Loaded = bLoaded;
  479. editor.OnEditorValueChanged += EditorValueChanged;
  480. }
  481. }
  482. public void Load(object item, Func<Type, CoreTable>? PageDataHandler)
  483. {
  484. ConfigureEditors();
  485. LoadEditorValues();
  486. foreach (var editor in Editors)
  487. {
  488. var editorValue = editor.GetValue();
  489. var entityValue = EditorGrid.GetPropertyValue(editor.ColumnName);
  490. if (!Equals(editorValue, entityValue))
  491. {
  492. editor.Loaded = false;
  493. editor.SetValue(entityValue);
  494. editor.Loaded = true;
  495. }
  496. }
  497. Editors.FirstOrDefault()?.SetFocus();
  498. Ready = true;
  499. }
  500. public Size MinimumSize() => new Size(800, GeneralHeight);
  501. public int Order() => PageOrder;
  502. }
  503. #endregion
  504. #region Loading + Editing Layout
  505. private decimal GetSequence(DynamicGridColumn column)
  506. {
  507. if (OnGetSequence != null)
  508. return OnGetSequence.Invoke(column);
  509. return 999;
  510. }
  511. private DynamicEditPage GetEditPage(string name)
  512. {
  513. var page = Pages.Where(x => x is DynamicEditPage page && page.Header == name).FirstOrDefault() as DynamicEditPage;
  514. if(page is null)
  515. {
  516. page = new DynamicEditPage(name);
  517. if (name == "General")
  518. {
  519. page.PageOrder = -1;
  520. }
  521. else
  522. {
  523. page.PageOrder = 0;
  524. }
  525. Pages.Add(page);
  526. }
  527. return page;
  528. }
  529. public void SetLayoutType<T>() where T : DynamicEditorGridLayout
  530. {
  531. LayoutType = typeof(T);
  532. }
  533. private void InitialiseLayout()
  534. {
  535. Layout = (Activator.CreateInstance(LayoutType ?? typeof(DefaultDynamicEditorGridLayout)) as DynamicEditorGridLayout)!;
  536. Layout.OnSelectPage += Layout_SelectPage;
  537. Content = Layout;
  538. }
  539. private void CreateLayout()
  540. {
  541. if(Layout is null)
  542. {
  543. InitialiseLayout();
  544. }
  545. foreach (var column in _columns.OrderBy(x => GetSequence(x)))
  546. {
  547. var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName);
  548. var editor = OnGetEditor?.Invoke(column);
  549. if (editor != null && iProp?.ShouldShowEditor() != true)
  550. {
  551. editor.Visible = Visible.Hidden;
  552. editor.Editable = Editable.Hidden;
  553. }
  554. if(editor is not null)
  555. {
  556. OnGridCustomiseEditor?.Invoke(this, column, editor);
  557. }
  558. if (editor != null && editor.Editable != Editable.Hidden)
  559. {
  560. var page = string.IsNullOrWhiteSpace(editor.Page) ? iProp is StandardProperty ? "General" : "Custom Fields" : editor.Page;
  561. var editPage = GetEditPage(page);
  562. editPage.AddEditor(column.ColumnName, editor);
  563. }
  564. }
  565. OnEditorCreated?.Invoke(this, 0, 800);
  566. }
  567. #endregion
  568. #region Pages
  569. private void Layout_SelectPage(IDynamicEditorPage page)
  570. {
  571. if (!page.Ready)
  572. using (new WaitCursor())
  573. {
  574. OnLoadPage?.Invoke(page);
  575. }
  576. OnSelectPage?.Invoke(this, null);
  577. }
  578. public void UnloadPages(bool saved)
  579. {
  580. if(Pages is not null)
  581. foreach (var page in Pages)
  582. if (page.Ready)
  583. OnUnloadPage?.Invoke(page, saved);
  584. }
  585. private void LoadPages()
  586. {
  587. if (Pages != null && Layout is not null)
  588. using (new WaitCursor())
  589. {
  590. foreach (var page in Pages)
  591. {
  592. page.Ready = false;
  593. page.EditorGrid = this;
  594. }
  595. Layout.LoadPages(Pages);
  596. if (PreloadPages)
  597. {
  598. foreach(var page in Pages)
  599. {
  600. OnLoadPage?.Invoke(page);
  601. }
  602. }
  603. }
  604. }
  605. public void Load(DynamicEditorPages pages)
  606. {
  607. Pages = pages;
  608. _columns = OnCustomiseColumns?.Invoke(this, null) ?? new DynamicGridColumns();
  609. CreateLayout();
  610. Reload();
  611. }
  612. #endregion
  613. }
  614. }