DynamicEditorGrid.xaml.cs 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  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
  474. {
  475. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) });
  476. fGeneralHeight += grid == EditorGrid ? iHeight + 5.0F : 0.0F;
  477. }
  478. double iWidth = element.DesiredWidth();
  479. if (iWidth == int.MaxValue)
  480. {
  481. element.HorizontalAlignment = HorizontalAlignment.Stretch;
  482. }
  483. else
  484. {
  485. element.HorizontalAlignment = HorizontalAlignment.Left;
  486. element.Width = iWidth;
  487. }
  488. element.SetValue(Grid.RowProperty, grid.RowDefinitions.Count - 1);
  489. element.SetValue(Grid.ColumnProperty, 1);
  490. grid.Children.Add(element);
  491. }
  492. }
  493. }
  494. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Created Editors: {0}", sw.ElapsedMilliseconds));
  495. //sw.Restart();
  496. OnEditorCreated?.Invoke(this, fGeneralHeight, 800);
  497. if(Details.Items[^1] is DynamicTabItem custom)
  498. {
  499. custom.Visibility = CustomGrid.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
  500. }
  501. //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Finalised: {0}", sw.ElapsedMilliseconds));
  502. //sw.Stop();
  503. }
  504. private Grid EnsureGrid(Dictionary<string, Grid> grids, string caption)
  505. {
  506. if (grids.ContainsKey(caption))
  507. return grids[caption];
  508. // Create Editor, ScrollViewer and TabItem for Dynamic Editor
  509. var result = new Grid
  510. {
  511. HorizontalAlignment = HorizontalAlignment.Stretch,
  512. VerticalAlignment = VerticalAlignment.Stretch,
  513. //Background = new SolidColorBrush(Colors.Blue),
  514. Margin = new Thickness(0, 2.5, 0, 2.5)
  515. };
  516. result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
  517. result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
  518. var scroll = new ScrollViewer
  519. {
  520. HorizontalAlignment = HorizontalAlignment.Stretch,
  521. VerticalAlignment = VerticalAlignment.Stretch,
  522. VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
  523. Padding = new Thickness(2)
  524. };
  525. scroll.Content = result;
  526. var border = new Border
  527. {
  528. BorderBrush = new SolidColorBrush(Colors.Gray),
  529. Background = new SolidColorBrush(Colors.White),
  530. BorderThickness = new Thickness(0.75)
  531. };
  532. border.Child = scroll;
  533. var tab = new DynamicTabItem();
  534. tab.Header = caption;
  535. tab.Content = border;
  536. if (Details.Items.Count == 0)
  537. Details.Items.Add(tab);
  538. else
  539. Details.Items.Insert(Details.Items.Count - 1, tab);
  540. grids[caption] = result;
  541. return result;
  542. }
  543. //List<TabItem> configuredpages = new List<TabItem>();
  544. private void Details_SelectionChanged(object sender, SelectionChangedEventArgs e)
  545. {
  546. if (bChanging || Details?.SelectedItem == null || e.OriginalSource != Details)
  547. return;
  548. bChanging = true;
  549. try
  550. {
  551. var tab = Details.SelectedItem as DynamicTabItem;
  552. if(tab is not null)
  553. {
  554. var page = tab.Content as IDynamicEditorPage;
  555. if (page is not null)
  556. {
  557. if (!page.Ready)
  558. using (new WaitCursor())
  559. {
  560. OnLoadPage?.Invoke(page);
  561. }
  562. }
  563. else
  564. {
  565. if (!_loaded || e.RemovedItems.Count == 0 || e.AddedItems.Count == 0 || e.AddedItems?[0] == e.RemovedItems?[0])
  566. return;
  567. //if (!configuredpages.Contains(tab))
  568. //{
  569. // ConfigureEditors(eds);
  570. // configuredpages.Add(tab);
  571. //}
  572. var selectedGrid = ((tab.Content as Border)?.Child as ScrollViewer)?.Content;
  573. var eds = editors
  574. .Where(x => x is BaseDynamicEditorControl control &&
  575. control.Parent == selectedGrid)
  576. .Select(x => (BaseDynamicEditorControl)x);
  577. foreach (var ed in eds)
  578. {
  579. var editorvalue = ed.GetValue();
  580. var entityvalue = OnGetPropertyValue?.Invoke(this, ed.ColumnName);
  581. if (!Equals(editorvalue, entityvalue))
  582. {
  583. ed.Loaded = false;
  584. ed.SetValue(entityvalue);
  585. ed.Loaded = true;
  586. }
  587. }
  588. }
  589. OnSelectPage?.Invoke(tab, null);
  590. }
  591. }
  592. finally
  593. {
  594. bChanging = false;
  595. }
  596. }
  597. public void UnloadPages(bool saved)
  598. {
  599. if(Pages is not null)
  600. foreach (var page in Pages)
  601. if (page.Ready)
  602. OnUnloadPage?.Invoke(page, saved);
  603. }
  604. private void Lookup_OnUpdateOtherEditor(string columnname, object value)
  605. {
  606. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  607. if (editor != null)
  608. CoreUtils.SetPropertyValue(editor, "Value", value);
  609. }
  610. private string FormatXML(string xml)
  611. {
  612. var result = "";
  613. var mStream = new MemoryStream();
  614. var writer = new XmlTextWriter(mStream, Encoding.Unicode);
  615. var document = new XmlDocument();
  616. try
  617. {
  618. // Load the XmlDocument with the XML.
  619. document.LoadXml(xml);
  620. writer.Formatting = Formatting.Indented;
  621. // Write the XML into a formatting XmlTextWriter
  622. document.WriteContentTo(writer);
  623. writer.Flush();
  624. mStream.Flush();
  625. // Have to rewind the MemoryStream in order to read
  626. // its contents.
  627. mStream.Position = 0;
  628. // Read MemoryStream contents into a StreamReader.
  629. var sReader = new StreamReader(mStream);
  630. // Extract the text from the StreamReader.
  631. var formattedXml = sReader.ReadToEnd();
  632. result = formattedXml;
  633. }
  634. catch (XmlException)
  635. {
  636. // Handle the exception
  637. }
  638. mStream.Close();
  639. writer.Close();
  640. return result;
  641. }
  642. public void EditLayout()
  643. {
  644. ClearPages();
  645. //UnloadEditorValues();
  646. var xaml = new GlobalConfiguration<ScreenLayout>(_layoutname).Load().XAML;
  647. if (string.IsNullOrWhiteSpace(xaml))
  648. {
  649. Details.Height = Details.ActualHeight;
  650. Details.Width = Details.ActualWidth;
  651. //xaml = XamlWriter.Save(GetParentWindow(Details));
  652. xaml = XamlWriter.Save(Details);
  653. }
  654. xaml = FormatXML(xaml);
  655. var scripteditor = new ScriptEditor(xaml, SyntaxLanguage.XAML);
  656. if (scripteditor.ShowDialog() == true)
  657. {
  658. var layout = new ScreenLayout { XAML = scripteditor.Script };
  659. new GlobalConfiguration<ScreenLayout>(_layoutname).Save(layout);
  660. Content = null;
  661. if (!LoadLayout(layout.XAML))
  662. if (!LoadLayout(xaml))
  663. CreateLayout();
  664. Details.ApplyTemplate();
  665. Application.Current.Dispatcher.Invoke(() =>
  666. {
  667. ConfigureEditors();
  668. LoadEditorValues();
  669. AddPages();
  670. DoReconfigureEditors();
  671. }, DispatcherPriority.Render);
  672. }
  673. }
  674. internal void ResetLayout()
  675. {
  676. new GlobalConfiguration<ScreenLayout>(_layoutname).Delete();
  677. ClearPages();
  678. //UnloadEditorValues();
  679. CreateLayout();
  680. LoadEditorValues();
  681. AddPages();
  682. DoReconfigureEditors();
  683. }
  684. private void LoadEditor(string columnname, object value)
  685. {
  686. }
  687. private void EditorValueChanged(IDynamicEditorControl sender, Dictionary<string, object> values)
  688. {
  689. //Logger.Send(LogType.Information, "", string.Format("DynamicEditorGrid.EditorValueChanged({0})", values.Keys.Count));
  690. var changededitors = new Dictionary<string, object?>();
  691. foreach (var key in values.Keys)
  692. {
  693. var changedcolumns = OnEditorValueChanged?.Invoke(this, key, values[key]);
  694. if (changedcolumns != null)
  695. foreach (var (change, value) in changedcolumns)
  696. if (editors.Any(x => x.ColumnName.Equals(change)) && !changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
  697. changededitors[change] = value;
  698. }
  699. if (changededitors.Any())
  700. LoadEditorValues(changededitors);
  701. DoReconfigureEditors();
  702. }
  703. private void LoadEditorValues(Dictionary<string, object?>? changededitors = null)
  704. {
  705. var columnnames = changededitors != null ? changededitors.Keys.ToArray() : editors.Select(x => x.ColumnName).ToArray();
  706. foreach (var columnname in columnnames)
  707. {
  708. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  709. if (editor == null)
  710. continue;
  711. var bLoaded = editor.Loaded;
  712. editor.Loaded = false;
  713. if (changededitors != null && changededitors.ContainsKey(columnname))
  714. {
  715. CoreUtils.SetPropertyValue(editor, "Value", changededitors[columnname]);
  716. }
  717. else
  718. {
  719. var curvalue = OnGetPropertyValue?.Invoke(this, columnname);
  720. try
  721. {
  722. CoreUtils.SetPropertyValue(editor, "Value", curvalue);
  723. }
  724. catch (Exception e)
  725. {
  726. MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}");
  727. }
  728. CoreUtils.SetPropertyValue(editor, "Changed", false);
  729. }
  730. editor.Loaded = bLoaded;
  731. editor.OnEditorValueChanged += EditorValueChanged;
  732. }
  733. }
  734. public virtual void DoReconfigureEditors()
  735. {
  736. ReconfigureEditors?.Invoke(this);
  737. }
  738. public void Load(string layoutname, DynamicEditorPages? pages = null)
  739. {
  740. _layoutname = layoutname;
  741. Pages = pages;
  742. //Stopwatch sw = new Stopwatch();
  743. //sw.Start();
  744. _columns = OnCustomiseColumns?.Invoke(this, null) ?? new DynamicGridColumns();
  745. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Columns: {0}", sw.ElapsedMilliseconds));
  746. //sw.Restart();
  747. var layout = new GlobalConfiguration<ScreenLayout>(_layoutname).Load();
  748. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Layout: {0}", sw.ElapsedMilliseconds));
  749. //sw.Restart();
  750. if (!LoadLayout(layout.XAML))
  751. CreateLayout();
  752. //Logger.Send(LogType.Information, "DEG.Load", String.Format("Created Layout: {0}", sw.ElapsedMilliseconds));
  753. //sw.Restart();
  754. }
  755. protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
  756. {
  757. base.OnRenderSizeChanged(sizeInfo);
  758. foreach (var columnname in editors.Select(x => x.ColumnName).ToArray())
  759. {
  760. var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname));
  761. if(editor is not null)
  762. {
  763. editor.Loaded = true;
  764. }
  765. }
  766. }
  767. public bool Unload()
  768. {
  769. ClearPages();
  770. var bChanged = false;
  771. foreach (var columnname in changes.Keys)
  772. {
  773. OnSetPropertyValue?.Invoke(this, columnname, changes[columnname]);
  774. bChanged = true;
  775. }
  776. return bChanged;
  777. }
  778. private void AddPages()
  779. {
  780. if (Pages != null)
  781. using (new WaitCursor())
  782. {
  783. foreach (var page in Pages.OrderBy(x => x.Order()).ThenBy(x => x.Caption()))
  784. {
  785. var tab = new DynamicTabItem();
  786. tab.Header = page.Caption();
  787. tab.Content = page;
  788. Details.Items.Insert(Details.Items.Count - 1, tab);
  789. pagemap[page] = tab;
  790. if (PreloadPages)
  791. OnLoadPage?.Invoke(page);
  792. page.EditorGrid = this;
  793. }
  794. }
  795. //if (Details.Items.Count <= 2)
  796. // ((TabItem)Details.Items[0]).Visibility = Visibility.Collapsed;
  797. }
  798. private void ClearPages()
  799. {
  800. foreach (var page in pagemap.Keys)
  801. {
  802. var tab = pagemap[page];
  803. tab.Content = null;
  804. Details.Items.Remove(tab);
  805. }
  806. pagemap.Clear();
  807. //if (_pages != null)
  808. //{
  809. // foreach (var page in _pages)
  810. // {
  811. // var tab = Details.Items.OfType<TabItem>().FirstOrDefault(x => x.Content.Equals(page));
  812. // if (tab != null)
  813. // {
  814. // tab.Content = null;
  815. // Details.Items.Remove(tab);
  816. // }
  817. // }
  818. //}
  819. }
  820. }
  821. }