DynamicEditorGrid.xaml.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. using System.Windows.Markup;
  13. using System.Windows.Media;
  14. using System.Windows.Threading;
  15. using System.Xml;
  16. using InABox.Clients;
  17. using InABox.Configuration;
  18. using InABox.Core;
  19. using InABox.WPF;
  20. using NPOI.SS.Formula.Functions;
  21. namespace InABox.DynamicGrid
  22. {
  23. /// <summary>
  24. /// Interaction logic for DynamicEditorGrid.xaml
  25. /// </summary>
  26. public delegate void OnUpdateOtherEditorHandler(string columnname, object value);
  27. public delegate Dictionary<string, object?> EditorValueChangedHandler(object sender, string name, object value);
  28. //public delegate Dictionary<object, object> EditorGetLookupsHandler(object sender, String column);
  29. public partial class DynamicEditorGrid : UserControl
  30. {
  31. public delegate void EditorCreatedHandler(object sender, double height, double width);
  32. public delegate Document? FindDocumentEvent(string FileName);
  33. public delegate Document? GetDocumentEvent(Guid id);
  34. public delegate object? GetPropertyValueHandler(object sender, string name);
  35. public delegate void SaveDocumentEvent(Document document);
  36. public delegate void SetPropertyValueHandler(object sender, string name, object value);
  37. public delegate object?[] GetItemsEvent();
  38. // Column Definitions as defined by calling model
  39. private DynamicGridColumns _columns;
  40. private string _layoutname = "";
  41. private bool _loaded;
  42. private bool bChanging;
  43. // List of Changed Editor Values (used when redesigning screen)
  44. private readonly Dictionary<string, object> changes = new();
  45. private Grid CustomGrid;
  46. private DynamicTabControl Details;
  47. private Grid EditorGrid;
  48. // Active Editor List
  49. private readonly List<IDynamicEditorControl> editors = new();
  50. private readonly Dictionary<IDynamicEditorPage, DynamicTabItem> pagemap = new();
  51. //Dictionary<IDynamicEditorPage, bool> loadedpages = new Dictionary<IDynamicEditorPage, bool>();
  52. public DynamicEditorGrid()
  53. {
  54. InitializeComponent();
  55. Loaded += DynamicEditorGrid_Loaded;
  56. }
  57. //private Dictionary<String, Tuple<FrameworkElement, Object, DynamicGridColumn>> editors = new Dictionary<string, Tuple<FrameworkElement, Object, DynamicGridColumn>>();
  58. public DynamicEditorPages? Pages { get; private set; }
  59. public bool PreloadPages { get; set; }
  60. public Type UnderlyingType { get; set; }
  61. public OnLoadPage? OnLoadPage { get; set; }
  62. public OnSelectPage? OnSelectPage { get; set; }
  63. public OnUnloadPage? OnUnloadPage { get; set; }
  64. //private void UnloadEditorValues()
  65. //{
  66. // foreach (string columnname in editors.Keys)
  67. // {
  68. // bool changed = (bool)CoreUtils.GetPropertyValue(editors[columnname], "Changed");
  69. // if (changed)
  70. // {
  71. // changes[columnname] = CoreUtils.GetPropertyValue(editors[columnname], "Value");
  72. // Dictionary<string, object> othervalues = CoreUtils.GetPropertyValue(editors[columnname], "OtherValues") as Dictionary<string, object>;
  73. // foreach (var field in othervalues.Keys)
  74. // {
  75. // List<String> comps = columnname.Split('.').ToList();
  76. // comps[comps.Count - 1] = field;
  77. // String actualname = String.Join(".", comps);
  78. // changes[actualname] = othervalues[field];
  79. // }
  80. // }
  81. // }
  82. //}
  83. public bool IsCustomLayout { get; private set; }
  84. public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor)
  85. {
  86. editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  87. return editor is not null;
  88. }
  89. public IDynamicEditorControl? FindEditor(string columnname)
  90. {
  91. TryFindEditor(columnname, out var editor);
  92. return editor;
  93. }
  94. public object? GetPropertyValue(string columnname)
  95. {
  96. return OnGetPropertyValue?.Invoke(this, columnname);
  97. }
  98. public event EditorCreatedHandler? OnEditorCreated;
  99. public event OnCustomiseColumns? OnCustomiseColumns;
  100. public event OnGetEditor? OnGetEditor;
  101. public event OnGridCustomiseEditor? OnGridCustomiseEditor;
  102. public event OnGetEditorSequence? OnGetSequence;
  103. public event GetPropertyValueHandler? OnGetPropertyValue;
  104. public event SetPropertyValueHandler? OnSetPropertyValue;
  105. public event EditorValueChangedHandler? OnEditorValueChanged;
  106. public event OnAfterEditorValueChanged? OnAfterEditorValueChanged;
  107. public event OnReconfigureEditors? OnReconfigureEditors;
  108. public event OnDefineFilter? OnDefineFilter;
  109. public event OnDefineLookup? OnDefineLookups;
  110. public event OnLookupsDefined? OnLookupsDefined;
  111. public event GetDocumentEvent? OnGetDocument;
  112. public event FindDocumentEvent? OnFindDocument;
  113. public event SaveDocumentEvent? OnSaveDocument;
  114. public event GetItemsEvent? GetItems;
  115. private void DynamicEditorGrid_Loaded(object sender, RoutedEventArgs e)
  116. {
  117. ConfigureEditors();
  118. LoadEditorValues();
  119. AddPages();
  120. ReconfigureEditors();
  121. //MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
  122. //MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
  123. //if (Keyboard.PrimaryDevice != null)
  124. //{
  125. // if (Keyboard.PrimaryDevice.ActiveSource != null)
  126. // {
  127. // var e1 = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Tab) { RoutedEvent = Keyboard.KeyDownEvent };
  128. // InputManager.Current.ProcessInput(e1);
  129. // }
  130. //}
  131. editors.FirstOrDefault()?.SetFocus();
  132. _loaded = true;
  133. }
  134. private void LoadLookupColumns(DynamicGridColumn column, Dictionary<string, string> othercolumns)
  135. {
  136. othercolumns.Clear();
  137. var comps = column.ColumnName.Split('.').ToList();
  138. comps.RemoveAt(comps.Count - 1);
  139. var prefix = string.Format("{0}.", string.Join(".", comps));
  140. var cols = _columns.Where(x => !x.ColumnName.Equals(column.ColumnName) && x.ColumnName.StartsWith(prefix));
  141. foreach (var col in cols)
  142. othercolumns[col.ColumnName.Replace(prefix, "")] = col.ColumnName;
  143. }
  144. private string GetCodeColumn(DynamicGridColumn column)
  145. {
  146. var comps = column.ColumnName.Split('.').ToList();
  147. comps.RemoveAt(comps.Count - 1);
  148. var prefix = string.Format("{0}.", string.Join(".", comps));
  149. var cols = _columns.Where(x => !x.ColumnName.Equals(column.ColumnName) && x.ColumnName.StartsWith(prefix));
  150. foreach (var col in cols)
  151. {
  152. var editor = OnGetEditor?.Invoke(col);
  153. if (editor is CodeEditor || editor is UniqueCodeEditor)
  154. return col.ColumnName.Split('.').Last();
  155. }
  156. return "";
  157. }
  158. private void ConfigureExpressionEditor(ExpressionEditorControl control)
  159. {
  160. control.GetItems += () => GetItems?.Invoke() ?? Array.Empty<object?>();
  161. }
  162. private void ConfigurePopupEditor(PopupEditorControl popup, DynamicGridColumn column, PopupEditor editor)
  163. {
  164. popup.ColumnName = column.ColumnName;
  165. LoadLookupColumns(column, popup.OtherColumns);
  166. if (popup.EditorDefinition is DataLookupEditor dataLookup)
  167. LoadLookupColumns(column, dataLookup.OtherColumns);
  168. popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  169. }
  170. private void ConfigureCodePopupEditor(CodePopupEditorControl popup, DynamicGridColumn column, CodePopupEditor editor)
  171. {
  172. popup.ColumnName = column.ColumnName;
  173. LoadLookupColumns(column, popup.OtherColumns);
  174. if (popup.EditorDefinition is DataLookupEditor dataLookup)
  175. LoadLookupColumns(column, dataLookup.OtherColumns);
  176. popup.CodeColumn = !string.IsNullOrEmpty(editor.CodeColumn) ? editor.CodeColumn : GetCodeColumn(column);
  177. popup.OnDefineFilter += (sender, type) => { return OnDefineFilter?.Invoke(sender, type); };
  178. popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  179. }
  180. private void ConfigureLookupEditor(LookupEditorControl lookup, DynamicGridColumn column, LookupEditor editor)
  181. {
  182. if (editor.LookupWidth != int.MaxValue)
  183. lookup.Width = editor.LookupWidth;
  184. lookup.ColumnName = column.ColumnName;
  185. LoadLookupColumns(column, lookup.OtherColumns);
  186. if (lookup.EditorDefinition is DataLookupEditor dataLookup)
  187. LoadLookupColumns(column, dataLookup.OtherColumns);
  188. lookup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  189. lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); };
  190. lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); };
  191. }
  192. private void ConfigureEnumEditor(LookupEditorControl lookup, DynamicGridColumn column, EnumLookupEditor editor)
  193. {
  194. if (editor.LookupWidth != int.MaxValue)
  195. lookup.Width = editor.LookupWidth;
  196. lookup.ColumnName = column.ColumnName;
  197. lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); };
  198. lookup.OnLookupsDefined += sender =>
  199. {
  200. //OnLookupsDefined?.Invoke(sender);
  201. };
  202. }
  203. private void ConfigureComboEditor(LookupEditorControl lookup, DynamicGridColumn column, ComboLookupEditor editor)
  204. {
  205. if (editor.LookupWidth != int.MaxValue)
  206. lookup.Width = editor.LookupWidth;
  207. lookup.ColumnName = column.ColumnName;
  208. lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); };
  209. lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); };
  210. }
  211. private void ConfigureMultiLookupEditor(MultiLookupEditorControl lookup, DynamicGridColumn column, ComboMultiLookupEditor editor)
  212. {
  213. if (editor.LookupWidth != int.MaxValue)
  214. lookup.Width = editor.LookupWidth;
  215. lookup.ColumnName = column.ColumnName;
  216. lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); };
  217. lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); };
  218. }
  219. private void ConfigureCheckListEditor(CheckListBoxEditorControl checks, DynamicGridColumn column, CheckListEditor editor)
  220. {
  221. checks.Width = editor.LookupWidth;
  222. checks.ColumnName = column.ColumnName;
  223. checks.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); };
  224. checks.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); };
  225. }
  226. private void ConfigureDocumentEditor(DocumentEditorControl document, DynamicGridColumn column, BaseDocumentEditor editor)
  227. {
  228. document.ColumnName = column.ColumnName;
  229. LoadLookupColumns(column, document.OtherColumns);
  230. if (document.EditorDefinition is DataLookupEditor dataLookup)
  231. LoadLookupColumns(column, dataLookup.OtherColumns);
  232. document.OnGetDocument += id => { return OnGetDocument?.Invoke(id); };
  233. document.OnSaveDocument += doc => { OnSaveDocument?.Invoke(doc); };
  234. document.OnFindDocument += file => { return OnFindDocument?.Invoke(file); };
  235. document.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor;
  236. document.Filter = editor.FileMask;
  237. }
  238. private void ConfigurePasswordEditor(PasswordEditorControl passwordEditorControl, DynamicGridColumn column, PasswordEditor passwordEditor)
  239. {
  240. passwordEditorControl.ViewButtonVisible = passwordEditor.ViewButtonVisible;
  241. }
  242. //private IEnumerable<BaseDynamicEditorControl> FindEditors(FrameworkElement element, DynamicGridColumn column)
  243. //{
  244. // if (element == null)
  245. // return new List<BaseDynamicEditorControl>();
  246. // if ((element is Border) && ((element as Border).Child is ScrollViewer))
  247. // return FindEditors(((element as Border).Child as ScrollViewer), column);
  248. // return element.FindVisualChildren<BaseDynamicEditorControl>().Where(x => x.ColumnName != null && x.ColumnName.Equals(column.ColumnName));
  249. //}
  250. private IEnumerable<BaseDynamicEditorControl> FindEditors(DynamicGridColumn column)
  251. {
  252. var results = new List<BaseDynamicEditorControl>();
  253. foreach (DynamicTabItem tab in Details.Items)
  254. {
  255. var border = tab.Content as Border;
  256. if (border != null)
  257. {
  258. var scroll = border.Child as ScrollViewer;
  259. if (scroll != null)
  260. {
  261. var grid = scroll.Content as Grid;
  262. if (grid != null)
  263. results.AddRange(grid.Children.OfType<BaseDynamicEditorControl>()
  264. .Where(x => string.Equals(x.ColumnName, column.ColumnName)));
  265. }
  266. }
  267. }
  268. //results.AddRange(FindEditors(tab.Content as FrameworkElement, column));
  269. return results;
  270. }
  271. private void ConfigureEditors()
  272. {
  273. if (editors.Any() && _columns != null)
  274. foreach (var column in _columns)
  275. {
  276. var editorname = column.ColumnName.Replace(".", "_");
  277. var
  278. Editors = FindEditors(
  279. column); //Details.FindVisualChildren<BaseDynamicEditorControl>().Where(x => x.ColumnName != null && x.ColumnName.Equals(column.ColumnName));
  280. foreach (var Editor in Editors)
  281. {
  282. var editor = Editor.EditorDefinition;
  283. //List<Object> parameters = editor.Parameters != null ? editor.Parameters.ToList() : new List<object>();
  284. if (Editor is LookupEditorControl lookupControl)
  285. {
  286. if (editor is LookupEditor lookupEditor)
  287. ConfigureLookupEditor(lookupControl, column, lookupEditor);
  288. else if (editor is EnumLookupEditor enumEditor)
  289. ConfigureEnumEditor(lookupControl, column, enumEditor);
  290. else if (editor is ComboLookupEditor comboEditor)
  291. ConfigureComboEditor(lookupControl, column, comboEditor);
  292. }
  293. else if(Editor is MultiLookupEditorControl multiLookupEditor && editor is ComboMultiLookupEditor comboMultiLookup)
  294. {
  295. ConfigureMultiLookupEditor(multiLookupEditor, column, comboMultiLookup);
  296. }
  297. else if (Editor is CheckListBoxEditorControl checkBoxControl && editor is CheckListEditor checkListEditor)
  298. {
  299. ConfigureCheckListEditor(checkBoxControl, column, checkListEditor);
  300. }
  301. else if (Editor is PopupEditorControl popupControl && editor is PopupEditor popupEditor)
  302. {
  303. ConfigurePopupEditor(popupControl, column, popupEditor);
  304. }
  305. else if (Editor is CodePopupEditorControl codePopupControl && editor is CodePopupEditor codePopupEditor)
  306. {
  307. ConfigureCodePopupEditor(codePopupControl, column, codePopupEditor);
  308. }
  309. else if (Editor is DocumentEditorControl documentEditorControl && editor is BaseDocumentEditor baseDocumentEditor)
  310. {
  311. ConfigureDocumentEditor(documentEditorControl, column, baseDocumentEditor);
  312. }
  313. else if (Editor is PasswordEditorControl passwordEditorControl && editor is PasswordEditor passwordEditor)
  314. {
  315. ConfigurePasswordEditor(passwordEditorControl, column, passwordEditor);
  316. }
  317. else if(Editor is ExpressionEditorControl expressionEditorControl && editor is ExpressionEditor expressionEditor)
  318. {
  319. ConfigureExpressionEditor(expressionEditorControl);
  320. }
  321. Editor.Configure();
  322. if (!editors.Any(x => x.ColumnName.Equals(Editor.ColumnName)))
  323. editors.Add(Editor);
  324. Editor.Loaded = true;
  325. }
  326. }
  327. }
  328. private bool LoadLayout(string xaml)
  329. {
  330. if (!string.IsNullOrWhiteSpace(xaml))
  331. try
  332. {
  333. IsCustomLayout = true;
  334. Content = null;
  335. Details = (XamlReader.Parse(xaml) as DynamicTabControl) ?? throw new Exception("XAML is not a DynamicTabControl");
  336. Content = Details;
  337. Details.ApplyTemplate();
  338. var iHeight = Details.Height > 0 ? Details.Height : 600;
  339. var iWidth = Details.Width > 0 ? Details.Width : 800;
  340. Details.Height = double.NaN;
  341. Details.Width = double.NaN;
  342. OnEditorCreated?.Invoke(this, iHeight, iWidth);
  343. return true;
  344. }
  345. catch (Exception e)
  346. {
  347. MessageBox.Show(string.Format("Unable to Load XAML!\n\n{0}", e.Message));
  348. }
  349. return false;
  350. }
  351. private decimal GetSequence(DynamicGridColumn column)
  352. {
  353. if (OnGetSequence != null)
  354. return OnGetSequence.Invoke(column);
  355. return 999;
  356. }
  357. private void CreateLayout()
  358. {
  359. //Stopwatch sw = new Stopwatch();
  360. //sw.Start();
  361. IsCustomLayout = false;
  362. Content = null;
  363. Details = new DynamicTabControl();
  364. Details.VerticalAlignment = VerticalAlignment.Stretch;
  365. Details.HorizontalAlignment = HorizontalAlignment.Stretch;
  366. Details.Name = "Details";
  367. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Created Tab Control: {0}", sw.ElapsedMilliseconds));
  368. //sw.Restart();
  369. var EditorGrids = new Dictionary<string, Grid>();
  370. CustomGrid = EnsureGrid(EditorGrids, "Custom Fields");
  371. EditorGrid = EnsureGrid(EditorGrids, "General");
  372. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Ensured Grids: {0}", sw.ElapsedMilliseconds));
  373. //sw.Restart();
  374. Details.SelectionChanged += Details_SelectionChanged;
  375. Content = Details;
  376. editors.Clear();
  377. double fGeneralHeight = 30; // Allow for Tab Header
  378. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Sorted Columns: {0}", sw.ElapsedMilliseconds));
  379. //sw.Restart();
  380. foreach (var column in _columns.OrderBy(x => GetSequence(x)))
  381. {
  382. var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName);
  383. var editor = OnGetEditor?.Invoke(column);
  384. if (editor != null && iProp?.ShouldShowEditor() != true)
  385. {
  386. editor.Visible = Visible.Hidden;
  387. editor.Editable = Editable.Hidden;
  388. }
  389. if(editor is not null)
  390. {
  391. OnGridCustomiseEditor?.Invoke(this, column, editor);
  392. }
  393. if (editor != null && editor.Editable != Editable.Hidden)
  394. {
  395. var page = string.IsNullOrWhiteSpace(editor.Page) ? iProp is StandardProperty ? "General" : "Custom Fields" : editor.Page;
  396. var grid = EnsureGrid(EditorGrids, page);
  397. //List<Object> parameters = editor.Parameters != null ? editor.Parameters.ToList() : new List<object>();
  398. //bool bParams = true;
  399. BaseDynamicEditorControl? element = null;
  400. element = editor switch
  401. {
  402. TextBoxEditor => new TextBoxEditorControl(),
  403. Core.RichTextEditor => new RichTextEditorControl(),
  404. URLEditor => new URLEditorControl(),
  405. CodeEditor or UniqueCodeEditor => new CodeEditorControl(),
  406. CheckBoxEditor => new CheckBoxEditorControl(),
  407. DateTimeEditor => new DateTimeEditorControl(),
  408. DateEditor dateEditor => new DateEditorControl { TodayVisible = dateEditor.TodayVisible },
  409. TimeOfDayEditor => new TimeOfDayEditorControl { NowButtonVisible = false },
  410. DurationEditor => new DurationEditorControl(),
  411. NotesEditor => new NotesEditorControl(),
  412. PINEditor => new PINEditorControl(),
  413. CheckListEditor => new CheckListBoxEditorControl(),
  414. MemoEditor => new MemoEditorControl(),
  415. JsonEditor => new JsonEditorControl(),
  416. LookupEditor => ClientFactory.IsSupported(((LookupEditor)editor).Type) ? new LookupEditorControl() : null,
  417. PopupEditor => ClientFactory.IsSupported(((PopupEditor)editor).Type) ? new PopupEditorControl() : null,
  418. CodePopupEditor => ClientFactory.IsSupported(((CodePopupEditor)editor).Type) ? new CodePopupEditorControl() : null,
  419. EnumLookupEditor or ComboLookupEditor => new LookupEditorControl(),
  420. ComboMultiLookupEditor => new MultiLookupEditorControl(),
  421. EmbeddedImageEditor imageEditor => new EmbeddedImageEditorControl
  422. {
  423. MaximumHeight = imageEditor.MaximumHeight,
  424. MaximumWidth = imageEditor.MaximumWidth,
  425. MaximumFileSize = imageEditor.MaximumFileSize
  426. },
  427. FileNameEditor fileNameEditor => new FileNameEditorControl
  428. {
  429. Filter = fileNameEditor.FileMask,
  430. AllowView = fileNameEditor.AllowView,
  431. RequireExisting = fileNameEditor.RequireExisting
  432. },
  433. FolderEditor folderEditor => new FolderEditorControl
  434. {
  435. InitialFolder = folderEditor.InitialFolder
  436. },
  437. MiscellaneousDocumentEditor => new DocumentEditorControl(),
  438. ImageDocumentEditor => new DocumentEditorControl(),
  439. VectorDocumentEditor => new DocumentEditorControl(),
  440. PDFDocumentEditor => new DocumentEditorControl(),
  441. PasswordEditor => new PasswordEditorControl(),
  442. CurrencyEditor => new CurrencyEditorControl(),
  443. DoubleEditor => new DoubleEditorControl(),
  444. IntegerEditor => new IntegerEditorControl(),
  445. Core.ScriptEditor scriptEditor => new ScriptEditorControl
  446. {
  447. SyntaxLanguage = scriptEditor.SyntaxLanguage
  448. },
  449. TimestampEditor => new TimestampEditorControl(),
  450. ColorEditor => new ColorEditorControl(),
  451. FilterEditor filter => new FilterEditorControl { FilterType = filter.Type! },
  452. ExpressionEditor expression => new ExpressionEditorControl(expression),
  453. _ => null,
  454. };
  455. if (element != null)
  456. {
  457. element.EditorDefinition = editor; //22
  458. element.IsEnabled = editor.Editable == Editable.Enabled;
  459. if (!string.IsNullOrWhiteSpace(editor.ToolTip))
  460. {
  461. element.ToolTip = new ToolTip() { Content = editor.ToolTip };
  462. }
  463. var label = new Label();
  464. label.Content = CoreUtils.Neatify(editor.Caption); // 2
  465. label.Margin = new Thickness(0F, 0F, 0F, 0F);
  466. label.HorizontalAlignment = HorizontalAlignment.Stretch;
  467. label.VerticalAlignment = VerticalAlignment.Stretch;
  468. label.HorizontalContentAlignment = HorizontalAlignment.Left;
  469. label.VerticalContentAlignment = VerticalAlignment.Center;
  470. label.SetValue(Grid.RowProperty, grid.RowDefinitions.Count);
  471. label.SetValue(Grid.ColumnProperty, 0);
  472. label.Visibility = string.IsNullOrWhiteSpace(editor.Caption) ? Visibility.Collapsed : Visibility.Visible;
  473. grid.Children.Add(label);
  474. element.ColumnName = column.ColumnName;
  475. element.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow;
  476. editors.Add(element);
  477. element.Margin = new Thickness(5F, 2.5F, 5F, 2.5F);
  478. double iHeight = element.DesiredHeight();
  479. if (iHeight == int.MaxValue)
  480. {
  481. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
  482. fGeneralHeight += grid == EditorGrid ? element.MinHeight + 5.0F : 0.0F;
  483. }
  484. else
  485. {
  486. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) });
  487. fGeneralHeight += grid == EditorGrid ? iHeight + 5.0F : 0.0F;
  488. }
  489. double iWidth = element.DesiredWidth();
  490. if (iWidth == int.MaxValue)
  491. {
  492. element.HorizontalAlignment = HorizontalAlignment.Stretch;
  493. }
  494. else
  495. {
  496. element.HorizontalAlignment = HorizontalAlignment.Left;
  497. element.Width = iWidth;
  498. }
  499. element.SetValue(Grid.RowProperty, grid.RowDefinitions.Count - 1);
  500. element.SetValue(Grid.ColumnProperty, 1);
  501. grid.Children.Add(element);
  502. }
  503. }
  504. }
  505. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Created Editors: {0}", sw.ElapsedMilliseconds));
  506. //sw.Restart();
  507. OnEditorCreated?.Invoke(this, fGeneralHeight, 800);
  508. if(Details.Items[^1] is DynamicTabItem custom)
  509. {
  510. custom.Visibility = CustomGrid.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
  511. }
  512. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Finalised: {0}", sw.ElapsedMilliseconds));
  513. //sw.Stop();
  514. }
  515. private Grid EnsureGrid(Dictionary<string, Grid> grids, string caption)
  516. {
  517. if (grids.ContainsKey(caption))
  518. return grids[caption];
  519. // Create Editor, ScrollViewer and TabItem for Dynamic Editor
  520. var result = new Grid
  521. {
  522. HorizontalAlignment = HorizontalAlignment.Stretch,
  523. VerticalAlignment = VerticalAlignment.Stretch,
  524. //Background = new SolidColorBrush(Colors.Blue),
  525. Margin = new Thickness(0, 2.5, 0, 2.5)
  526. };
  527. result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
  528. result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  529. var scroll = new ScrollViewer
  530. {
  531. HorizontalAlignment = HorizontalAlignment.Stretch,
  532. VerticalAlignment = VerticalAlignment.Stretch,
  533. VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
  534. Padding = new Thickness(2)
  535. };
  536. scroll.Content = result;
  537. var border = new Border
  538. {
  539. BorderBrush = new SolidColorBrush(Colors.Gray),
  540. Background = new SolidColorBrush(Colors.White),
  541. BorderThickness = new Thickness(0.75)
  542. };
  543. border.Child = scroll;
  544. var tab = new DynamicTabItem();
  545. tab.Header = caption;
  546. tab.Content = border;
  547. if (Details.Items.Count == 0)
  548. Details.Items.Add(tab);
  549. else
  550. Details.Items.Insert(Details.Items.Count - 1, tab);
  551. grids[caption] = result;
  552. return result;
  553. }
  554. //List<TabItem> configuredpages = new List<TabItem>();
  555. private void Details_SelectionChanged(object sender, SelectionChangedEventArgs e)
  556. {
  557. if (bChanging || Details?.SelectedItem == null || e.OriginalSource != Details)
  558. return;
  559. bChanging = true;
  560. try
  561. {
  562. var tab = Details.SelectedItem as DynamicTabItem;
  563. if(tab is not null)
  564. {
  565. var page = tab.Content as IDynamicEditorPage;
  566. if (page is not null)
  567. {
  568. if (!page.Ready)
  569. using (new WaitCursor())
  570. {
  571. OnLoadPage?.Invoke(page);
  572. }
  573. }
  574. else
  575. {
  576. if (!_loaded || e.RemovedItems.Count == 0 || e.AddedItems.Count == 0 || e.AddedItems?[0] == e.RemovedItems?[0])
  577. return;
  578. //if (!configuredpages.Contains(tab))
  579. //{
  580. // ConfigureEditors(eds);
  581. // configuredpages.Add(tab);
  582. //}
  583. var selectedGrid = ((tab.Content as Border)?.Child as ScrollViewer)?.Content;
  584. var eds = editors
  585. .Where(x => x is BaseDynamicEditorControl control &&
  586. control.Parent == selectedGrid)
  587. .Select(x => (BaseDynamicEditorControl)x);
  588. foreach (var ed in eds)
  589. {
  590. var editorvalue = ed.GetValue();
  591. var entityvalue = OnGetPropertyValue?.Invoke(this, ed.ColumnName);
  592. if (!Equals(editorvalue, entityvalue))
  593. {
  594. ed.Loaded = false;
  595. ed.SetValue(entityvalue);
  596. ed.Loaded = true;
  597. }
  598. }
  599. }
  600. OnSelectPage?.Invoke(tab, null);
  601. }
  602. }
  603. finally
  604. {
  605. bChanging = false;
  606. }
  607. }
  608. public void UnloadPages(bool saved)
  609. {
  610. if(Pages is not null)
  611. foreach (var page in Pages)
  612. if (page.Ready)
  613. OnUnloadPage?.Invoke(page, saved);
  614. }
  615. private void Lookup_OnUpdateOtherEditor(string columnname, object value)
  616. {
  617. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  618. if (editor != null)
  619. CoreUtils.SetPropertyValue(editor, "Value", value);
  620. }
  621. private string FormatXML(string xml)
  622. {
  623. var result = "";
  624. var mStream = new MemoryStream();
  625. var writer = new XmlTextWriter(mStream, Encoding.Unicode);
  626. var document = new XmlDocument();
  627. try
  628. {
  629. // Load the XmlDocument with the XML.
  630. document.LoadXml(xml);
  631. writer.Formatting = Formatting.Indented;
  632. // Write the XML into a formatting XmlTextWriter
  633. document.WriteContentTo(writer);
  634. writer.Flush();
  635. mStream.Flush();
  636. // Have to rewind the MemoryStream in order to read
  637. // its contents.
  638. mStream.Position = 0;
  639. // Read MemoryStream contents into a StreamReader.
  640. var sReader = new StreamReader(mStream);
  641. // Extract the text from the StreamReader.
  642. var formattedXml = sReader.ReadToEnd();
  643. result = formattedXml;
  644. }
  645. catch (XmlException)
  646. {
  647. // Handle the exception
  648. }
  649. mStream.Close();
  650. writer.Close();
  651. return result;
  652. }
  653. public void EditLayout()
  654. {
  655. ClearPages();
  656. //UnloadEditorValues();
  657. var xaml = new GlobalConfiguration<ScreenLayout>(_layoutname).Load().XAML;
  658. if (string.IsNullOrWhiteSpace(xaml))
  659. {
  660. Details.Height = Details.ActualHeight;
  661. Details.Width = Details.ActualWidth;
  662. //xaml = XamlWriter.Save(GetParentWindow(Details));
  663. xaml = XamlWriter.Save(Details);
  664. }
  665. xaml = FormatXML(xaml);
  666. var scripteditor = new ScriptEditor(xaml, SyntaxLanguage.XAML);
  667. if (scripteditor.ShowDialog() == true)
  668. {
  669. var layout = new ScreenLayout { XAML = scripteditor.Script };
  670. new GlobalConfiguration<ScreenLayout>(_layoutname).Save(layout);
  671. Content = null;
  672. if (!LoadLayout(layout.XAML))
  673. if (!LoadLayout(xaml))
  674. CreateLayout();
  675. Details.ApplyTemplate();
  676. Application.Current.Dispatcher.Invoke(() =>
  677. {
  678. ConfigureEditors();
  679. LoadEditorValues();
  680. AddPages();
  681. ReconfigureEditors();
  682. }, DispatcherPriority.Render);
  683. }
  684. }
  685. internal void ResetLayout()
  686. {
  687. new GlobalConfiguration<ScreenLayout>(_layoutname).Delete();
  688. ClearPages();
  689. //UnloadEditorValues();
  690. CreateLayout();
  691. LoadEditorValues();
  692. AddPages();
  693. ReconfigureEditors();
  694. }
  695. private void LoadEditor(string columnname, object value)
  696. {
  697. }
  698. private void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object> values)
  699. {
  700. var changededitors = new Dictionary<string, object?>();
  701. void ExtractChanged(Dictionary<String, object?>? columns)
  702. {
  703. if (columns != null)
  704. foreach (var (change, value) in columns)
  705. if (editors.Any(x => x.ColumnName.Equals(change)) && !changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
  706. changededitors[change] = value;
  707. }
  708. foreach (var key in values.Keys)
  709. {
  710. var changedcolumns = OnEditorValueChanged?.Invoke(this, key, values[key]);
  711. ExtractChanged(changedcolumns);
  712. }
  713. var afterchanged = OnAfterEditorValueChanged?.Invoke(this, sender.ColumnName);
  714. ExtractChanged(afterchanged);
  715. if (changededitors.Any())
  716. LoadEditorValues(changededitors);
  717. ReconfigureEditors();
  718. }
  719. private void LoadEditorValues(Dictionary<string, object?>? changededitors = null)
  720. {
  721. var columnnames = changededitors != null ? changededitors.Keys.ToArray() : editors.Select(x => x.ColumnName).ToArray();
  722. foreach (var columnname in columnnames)
  723. {
  724. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  725. if (editor == null)
  726. continue;
  727. var bLoaded = editor.Loaded;
  728. editor.Loaded = false;
  729. if (changededitors != null && changededitors.ContainsKey(columnname))
  730. {
  731. CoreUtils.SetPropertyValue(editor, "Value", changededitors[columnname]);
  732. }
  733. else
  734. {
  735. var curvalue = OnGetPropertyValue?.Invoke(this, columnname);
  736. try
  737. {
  738. CoreUtils.SetPropertyValue(editor, "Value", curvalue);
  739. }
  740. catch (Exception e)
  741. {
  742. MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}");
  743. }
  744. CoreUtils.SetPropertyValue(editor, "Changed", false);
  745. }
  746. editor.Loaded = bLoaded;
  747. editor.OnEditorValueChanged += EditorValueChanged;
  748. }
  749. }
  750. public virtual void ReconfigureEditors()
  751. {
  752. OnReconfigureEditors?.Invoke(this);
  753. }
  754. public void Load(string layoutname, DynamicEditorPages? pages = null)
  755. {
  756. _layoutname = layoutname;
  757. Pages = pages;
  758. //Stopwatch sw = new Stopwatch();
  759. //sw.Start();
  760. _columns = OnCustomiseColumns?.Invoke(this, null) ?? new DynamicGridColumns();
  761. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Columns: {0}", sw.ElapsedMilliseconds));
  762. //sw.Restart();
  763. var layout = new GlobalConfiguration<ScreenLayout>(_layoutname).Load();
  764. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Layout: {0}", sw.ElapsedMilliseconds));
  765. //sw.Restart();
  766. if (!LoadLayout(layout.XAML))
  767. CreateLayout();
  768. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Created Layout: {0}", sw.ElapsedMilliseconds));
  769. //sw.Restart();
  770. }
  771. protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
  772. {
  773. base.OnRenderSizeChanged(sizeInfo);
  774. foreach (var columnname in editors.Select(x => x.ColumnName).ToArray())
  775. {
  776. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  777. if(editor is not null)
  778. {
  779. editor.Loaded = true;
  780. }
  781. }
  782. }
  783. public bool Unload()
  784. {
  785. ClearPages();
  786. var bChanged = false;
  787. foreach (var columnname in changes.Keys)
  788. {
  789. OnSetPropertyValue?.Invoke(this, columnname, changes[columnname]);
  790. bChanged = true;
  791. }
  792. return bChanged;
  793. }
  794. private void AddPages()
  795. {
  796. if (Pages != null)
  797. using (new WaitCursor())
  798. {
  799. foreach (var page in Pages.OrderBy(x => x.Order()).ThenBy(x => x.Caption()))
  800. {
  801. var tab = new DynamicTabItem();
  802. tab.Header = page.Caption();
  803. tab.Content = page;
  804. Details.Items.Insert(Details.Items.Count - 1, tab);
  805. pagemap[page] = tab;
  806. if (PreloadPages)
  807. OnLoadPage?.Invoke(page);
  808. page.EditorGrid = this;
  809. }
  810. }
  811. //if (Details.Items.Count <= 2)
  812. // ((TabItem)Details.Items[0]).Visibility = Visibility.Collapsed;
  813. }
  814. private void ClearPages()
  815. {
  816. foreach (var page in pagemap.Keys)
  817. {
  818. var tab = pagemap[page];
  819. tab.Content = null;
  820. Details.Items.Remove(tab);
  821. }
  822. pagemap.Clear();
  823. //if (_pages != null)
  824. //{
  825. // foreach (var page in _pages)
  826. // {
  827. // var tab = Details.Items.OfType<TabItem>().FirstOrDefault(x => x.Content.Equals(page));
  828. // if (tab != null)
  829. // {
  830. // tab.Content = null;
  831. // Details.Items.Remove(tab);
  832. // }
  833. // }
  834. //}
  835. }
  836. }
  837. }