DynamicEditorGrid.xaml.cs 41 KB

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