using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Threading; using System.Xml; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.WPF; using NPOI.SS.Formula.Functions; namespace InABox.DynamicGrid { /// /// Interaction logic for DynamicEditorGrid.xaml /// public delegate void OnUpdateOtherEditorHandler(string columnname, object value); public delegate Dictionary EditorValueChangedHandler(object sender, string name, object value); //public delegate Dictionary EditorGetLookupsHandler(object sender, String column); public partial class DynamicEditorGrid : UserControl { public delegate void EditorCreatedHandler(object sender, double height, double width); public delegate Document? FindDocumentEvent(string FileName); public delegate Document? GetDocumentEvent(Guid id); public delegate object? GetPropertyValueHandler(object sender, string name); public delegate void SaveDocumentEvent(Document document); public delegate void SetPropertyValueHandler(object sender, string name, object value); // Column Definitions as defined by calling model private DynamicGridColumns _columns; private string _layoutname = ""; private bool _loaded; private bool bChanging; // List of Changed Editor Values (used when redesigning screen) private readonly Dictionary changes = new(); private Grid CustomGrid; private DynamicTabControl Details; private Grid EditorGrid; // Active Editor List private readonly List editors = new(); private readonly Dictionary pagemap = new(); //Dictionary loadedpages = new Dictionary(); public DynamicEditorGrid() { InitializeComponent(); Loaded += DynamicEditorGrid_Loaded; } //private Dictionary> editors = new Dictionary>(); public DynamicEditorPages? Pages { get; private set; } public bool PreloadPages { get; set; } public Type UnderlyingType { get; set; } public OnLoadPage? OnLoadPage { get; set; } public OnSelectPage? OnSelectPage { get; set; } public OnUnloadPage? OnUnloadPage { get; set; } //private void UnloadEditorValues() //{ // foreach (string columnname in editors.Keys) // { // bool changed = (bool)CoreUtils.GetPropertyValue(editors[columnname], "Changed"); // if (changed) // { // changes[columnname] = CoreUtils.GetPropertyValue(editors[columnname], "Value"); // Dictionary othervalues = CoreUtils.GetPropertyValue(editors[columnname], "OtherValues") as Dictionary; // foreach (var field in othervalues.Keys) // { // List comps = columnname.Split('.').ToList(); // comps[comps.Count - 1] = field; // String actualname = String.Join(".", comps); // changes[actualname] = othervalues[field]; // } // } // } //} public bool IsCustomLayout { get; private set; } public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor) { editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname)); return editor is not null; } public IDynamicEditorControl? FindEditor(string columnname) { TryFindEditor(columnname, out var editor); return editor; } public object? GetPropertyValue(string columnname) { return OnGetPropertyValue?.Invoke(this, columnname); } public event EditorCreatedHandler? OnEditorCreated; public event OnCustomiseColumns? OnCustomiseColumns; public event OnGetEditor? OnGetEditor; public event OnGridCustomiseEditor? OnGridCustomiseEditor; public event OnGetEditorSequence? OnGetSequence; public event GetPropertyValueHandler? OnGetPropertyValue; public event SetPropertyValueHandler? OnSetPropertyValue; public event EditorValueChangedHandler? OnEditorValueChanged; public event OnReconfigureEditors? ReconfigureEditors; public event OnDefineFilter? OnDefineFilter; public event OnDefineLookup? OnDefineLookups; public event OnLookupsDefined? OnLookupsDefined; public event GetDocumentEvent? OnGetDocument; public event FindDocumentEvent? OnFindDocument; public event SaveDocumentEvent? OnSaveDocument; private void DynamicEditorGrid_Loaded(object sender, RoutedEventArgs e) { ConfigureEditors(); LoadEditorValues(); AddPages(); DoReconfigureEditors(); //MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); //MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); //if (Keyboard.PrimaryDevice != null) //{ // if (Keyboard.PrimaryDevice.ActiveSource != null) // { // var e1 = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Tab) { RoutedEvent = Keyboard.KeyDownEvent }; // InputManager.Current.ProcessInput(e1); // } //} editors.FirstOrDefault()?.SetFocus(); _loaded = true; } private void LoadLookupColumns(DynamicGridColumn column, Dictionary othercolumns) { othercolumns.Clear(); var comps = column.ColumnName.Split('.').ToList(); comps.RemoveAt(comps.Count - 1); var prefix = string.Format("{0}.", string.Join(".", comps)); var cols = _columns.Where(x => !x.ColumnName.Equals(column.ColumnName) && x.ColumnName.StartsWith(prefix)); foreach (var col in cols) othercolumns[col.ColumnName.Replace(prefix, "")] = col.ColumnName; } private string GetCodeColumn(DynamicGridColumn column) { var comps = column.ColumnName.Split('.').ToList(); comps.RemoveAt(comps.Count - 1); var prefix = string.Format("{0}.", string.Join(".", comps)); var cols = _columns.Where(x => !x.ColumnName.Equals(column.ColumnName) && x.ColumnName.StartsWith(prefix)); foreach (var col in cols) { var editor = OnGetEditor?.Invoke(col); if (editor is CodeEditor || editor is UniqueCodeEditor) return col.ColumnName.Split('.').Last(); } return ""; } private void ConfigurePopupEditor(PopupEditorControl popup, DynamicGridColumn column, PopupEditor editor) { popup.ColumnName = column.ColumnName; LoadLookupColumns(column, popup.OtherColumns); if (popup.EditorDefinition is DataLookupEditor dataLookup) LoadLookupColumns(column, dataLookup.OtherColumns); popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor; } private void ConfigureCodePopupEditor(CodePopupEditorControl popup, DynamicGridColumn column, CodePopupEditor editor) { popup.ColumnName = column.ColumnName; LoadLookupColumns(column, popup.OtherColumns); if (popup.EditorDefinition is DataLookupEditor dataLookup) LoadLookupColumns(column, dataLookup.OtherColumns); popup.CodeColumn = !string.IsNullOrEmpty(editor.CodeColumn) ? editor.CodeColumn : GetCodeColumn(column); popup.OnDefineFilter += (sender, type) => { return OnDefineFilter?.Invoke(sender, type); }; popup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor; } private void ConfigureLookupEditor(LookupEditorControl lookup, DynamicGridColumn column, LookupEditor editor) { if (editor.LookupWidth != int.MaxValue) lookup.Width = editor.LookupWidth; lookup.ColumnName = column.ColumnName; LoadLookupColumns(column, lookup.OtherColumns); if (lookup.EditorDefinition is DataLookupEditor dataLookup) LoadLookupColumns(column, dataLookup.OtherColumns); lookup.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor; lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); }; } private void ConfigureEnumEditor(LookupEditorControl lookup, DynamicGridColumn column, EnumLookupEditor editor) { if (editor.LookupWidth != int.MaxValue) lookup.Width = editor.LookupWidth; lookup.ColumnName = column.ColumnName; lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; lookup.OnLookupsDefined += sender => { //OnLookupsDefined?.Invoke(sender); }; } private void ConfigureComboEditor(LookupEditorControl lookup, DynamicGridColumn column, ComboLookupEditor editor) { if (editor.LookupWidth != int.MaxValue) lookup.Width = editor.LookupWidth; lookup.ColumnName = column.ColumnName; lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); }; } private void ConfigureMultiLookupEditor(MultiLookupEditorControl lookup, DynamicGridColumn column, ComboMultiLookupEditor editor) { if (editor.LookupWidth != int.MaxValue) lookup.Width = editor.LookupWidth; lookup.ColumnName = column.ColumnName; lookup.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; lookup.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); }; } private void ConfigureCheckListEditor(CheckListBoxEditorControl checks, DynamicGridColumn column, CheckListEditor editor) { checks.Width = editor.LookupWidth; checks.ColumnName = column.ColumnName; checks.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; checks.OnLookupsDefined += sender => { OnLookupsDefined?.Invoke(sender); }; } private void ConfigureDocumentEditor(DocumentEditorControl document, DynamicGridColumn column, BaseDocumentEditor editor) { document.ColumnName = column.ColumnName; LoadLookupColumns(column, document.OtherColumns); if (document.EditorDefinition is DataLookupEditor dataLookup) LoadLookupColumns(column, dataLookup.OtherColumns); document.OnGetDocument += id => { return OnGetDocument?.Invoke(id); }; document.OnSaveDocument += doc => { OnSaveDocument?.Invoke(doc); }; document.OnFindDocument += file => { return OnFindDocument?.Invoke(file); }; document.OnUpdateOtherEditor += Lookup_OnUpdateOtherEditor; document.Filter = editor.FileMask; } private void ConfigurePasswordEditor(PasswordEditorControl passwordEditorControl, DynamicGridColumn column, PasswordEditor passwordEditor) { passwordEditorControl.ViewButtonVisible = passwordEditor.ViewButtonVisible; } //private IEnumerable FindEditors(FrameworkElement element, DynamicGridColumn column) //{ // if (element == null) // return new List(); // if ((element is Border) && ((element as Border).Child is ScrollViewer)) // return FindEditors(((element as Border).Child as ScrollViewer), column); // return element.FindVisualChildren().Where(x => x.ColumnName != null && x.ColumnName.Equals(column.ColumnName)); //} private IEnumerable FindEditors(DynamicGridColumn column) { var results = new List(); foreach (DynamicTabItem tab in Details.Items) { var border = tab.Content as Border; if (border != null) { var scroll = border.Child as ScrollViewer; if (scroll != null) { var grid = scroll.Content as Grid; if (grid != null) results.AddRange(grid.Children.OfType() .Where(x => string.Equals(x.ColumnName, column.ColumnName))); } } } //results.AddRange(FindEditors(tab.Content as FrameworkElement, column)); return results; } private void ConfigureEditors() { if (editors.Any() && _columns != null) foreach (var column in _columns) { var editorname = column.ColumnName.Replace(".", "_"); var Editors = FindEditors( column); //Details.FindVisualChildren().Where(x => x.ColumnName != null && x.ColumnName.Equals(column.ColumnName)); foreach (var Editor in Editors) { var editor = Editor.EditorDefinition; //List parameters = editor.Parameters != null ? editor.Parameters.ToList() : new List(); if (Editor is LookupEditorControl lookupControl) { if (editor is LookupEditor lookupEditor) ConfigureLookupEditor(lookupControl, column, lookupEditor); else if (editor is EnumLookupEditor enumEditor) ConfigureEnumEditor(lookupControl, column, enumEditor); else if (editor is ComboLookupEditor comboEditor) ConfigureComboEditor(lookupControl, column, comboEditor); } else if(Editor is MultiLookupEditorControl multiLookupEditor && editor is ComboMultiLookupEditor comboMultiLookup) { ConfigureMultiLookupEditor(multiLookupEditor, column, comboMultiLookup); } else if (Editor is CheckListBoxEditorControl checkBoxControl && editor is CheckListEditor checkListEditor) { ConfigureCheckListEditor(checkBoxControl, column, checkListEditor); } else if (Editor is PopupEditorControl popupControl && editor is PopupEditor popupEditor) { ConfigurePopupEditor(popupControl, column, popupEditor); } else if (Editor is CodePopupEditorControl codePopupControl && editor is CodePopupEditor codePopupEditor) { ConfigureCodePopupEditor(codePopupControl, column, codePopupEditor); } else if (Editor is DocumentEditorControl documentEditorControl && editor is BaseDocumentEditor baseDocumentEditor) { ConfigureDocumentEditor(documentEditorControl, column, baseDocumentEditor); } else if (Editor is PasswordEditorControl passwordEditorControl && editor is PasswordEditor passwordEditor) { ConfigurePasswordEditor(passwordEditorControl, column, passwordEditor); } Editor.Configure(); if (!editors.Any(x => x.ColumnName.Equals(Editor.ColumnName))) editors.Add(Editor); Editor.Loaded = true; } } } private bool LoadLayout(string xaml) { if (!string.IsNullOrWhiteSpace(xaml)) try { IsCustomLayout = true; Content = null; Details = (XamlReader.Parse(xaml) as DynamicTabControl) ?? throw new Exception("XAML is not a DynamicTabControl"); Content = Details; Details.ApplyTemplate(); var iHeight = Details.Height > 0 ? Details.Height : 600; var iWidth = Details.Width > 0 ? Details.Width : 800; Details.Height = double.NaN; Details.Width = double.NaN; OnEditorCreated?.Invoke(this, iHeight, iWidth); return true; } catch (Exception e) { MessageBox.Show(string.Format("Unable to Load XAML!\n\n{0}", e.Message)); } return false; } private decimal GetSequence(DynamicGridColumn column) { if (OnGetSequence != null) return OnGetSequence.Invoke(column); return 999; } private void CreateLayout() { //Stopwatch sw = new Stopwatch(); //sw.Start(); IsCustomLayout = false; Content = null; Details = new DynamicTabControl(); Details.VerticalAlignment = VerticalAlignment.Stretch; Details.HorizontalAlignment = HorizontalAlignment.Stretch; Details.Name = "Details"; //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Created Tab Control: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); var EditorGrids = new Dictionary(); CustomGrid = EnsureGrid(EditorGrids, "Custom Fields"); EditorGrid = EnsureGrid(EditorGrids, "General"); //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Ensured Grids: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); Details.SelectionChanged += Details_SelectionChanged; Content = Details; editors.Clear(); double fGeneralHeight = 30; // Allow for Tab Header //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Sorted Columns: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); foreach (var column in _columns.OrderBy(x => GetSequence(x))) { var iProp = DatabaseSchema.Property(UnderlyingType, column.ColumnName); var editor = OnGetEditor?.Invoke(column); if (editor != null && iProp?.ShouldShowEditor() != true) { editor.Visible = Visible.Hidden; editor.Editable = Editable.Hidden; } if(editor is not null) { OnGridCustomiseEditor?.Invoke(this, column, editor); } if (editor != null && editor.Editable != Editable.Hidden) { var page = string.IsNullOrWhiteSpace(editor.Page) ? iProp is StandardProperty ? "General" : "Custom Fields" : editor.Page; var grid = EnsureGrid(EditorGrids, page); //List parameters = editor.Parameters != null ? editor.Parameters.ToList() : new List(); //bool bParams = true; BaseDynamicEditorControl? element = null; element = editor switch { TextBoxEditor => new TextBoxEditorControl(), Core.RichTextEditor => new RichTextEditorControl(), URLEditor => new URLEditorControl(), CodeEditor or UniqueCodeEditor => new CodeEditorControl(), CheckBoxEditor => new CheckBoxEditorControl(), DateTimeEditor => new DateTimeEditorControl(), DateEditor dateEditor => new DateEditorControl { TodayVisible = dateEditor.TodayVisible }, TimeOfDayEditor => new TimeOfDayEditorControl { NowButtonVisible = false }, DurationEditor => new DurationEditorControl(), NotesEditor => new NotesEditorControl(), PINEditor => new PINEditorControl(), CheckListEditor => new CheckListBoxEditorControl(), MemoEditor => new MemoEditorControl(), JsonEditor => new JsonEditorControl(), LookupEditor => ClientFactory.IsSupported(((LookupEditor)editor).Type) ? new LookupEditorControl() : null, PopupEditor => ClientFactory.IsSupported(((PopupEditor)editor).Type) ? new PopupEditorControl() : null, CodePopupEditor => ClientFactory.IsSupported(((CodePopupEditor)editor).Type) ? new CodePopupEditorControl() : null, EnumLookupEditor or ComboLookupEditor => new LookupEditorControl(), ComboMultiLookupEditor => new MultiLookupEditorControl(), EmbeddedImageEditor imageEditor => new EmbeddedImageEditorControl { MaximumHeight = imageEditor.MaximumHeight, MaximumWidth = imageEditor.MaximumWidth, MaximumFileSize = imageEditor.MaximumFileSize }, FileNameEditor fileNameEditor => new FileNameEditorControl { Filter = fileNameEditor.FileMask, AllowView = fileNameEditor.AllowView, RequireExisting = fileNameEditor.RequireExisting }, FolderEditor folderEditor => new FolderEditorControl { InitialFolder = folderEditor.InitialFolder }, MiscellaneousDocumentEditor => new DocumentEditorControl(), ImageDocumentEditor => new DocumentEditorControl(), VectorDocumentEditor => new DocumentEditorControl(), PDFDocumentEditor => new DocumentEditorControl(), PasswordEditor => new PasswordEditorControl(), CurrencyEditor => new CurrencyEditorControl(), DoubleEditor => new DoubleEditorControl(), IntegerEditor => new IntegerEditorControl(), Core.ScriptEditor scriptEditor => new ScriptEditorControl { SyntaxLanguage = scriptEditor.SyntaxLanguage }, TimestampEditor => new TimestampEditorControl(), ColorEditor => new ColorEditorControl(), FilterEditor filter => new FilterEditorControl { FilterType = filter.Type! }, ExpressionEditor expression => new ExpressionEditorControl(), _ => null, }; if (element != null) { element.EditorDefinition = editor; //22 element.IsEnabled = editor.Editable == Editable.Enabled; if (!string.IsNullOrWhiteSpace(editor.ToolTip)) { element.ToolTip = new ToolTip() { Content = editor.ToolTip }; } var label = new Label(); label.Content = CoreUtils.Neatify(editor.Caption); // 2 label.Margin = new Thickness(0F, 0F, 0F, 0F); label.HorizontalAlignment = HorizontalAlignment.Stretch; label.VerticalAlignment = VerticalAlignment.Stretch; label.HorizontalContentAlignment = HorizontalAlignment.Left; label.VerticalContentAlignment = VerticalAlignment.Center; label.SetValue(Grid.RowProperty, grid.RowDefinitions.Count); label.SetValue(Grid.ColumnProperty, 0); label.Visibility = string.IsNullOrWhiteSpace(editor.Caption) ? Visibility.Collapsed : Visibility.Visible; grid.Children.Add(label); element.ColumnName = column.ColumnName; element.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow; editors.Add(element); element.Margin = new Thickness(5F, 2.5F, 5F, 2.5F); double iHeight = element.DesiredHeight(); if (iHeight == int.MaxValue) { grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); fGeneralHeight += grid == EditorGrid ? element.MinHeight + 5.0F : 0.0F; } else { grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(iHeight + 5.0F) }); fGeneralHeight += grid == EditorGrid ? iHeight + 5.0F : 0.0F; } double iWidth = element.DesiredWidth(); if (iWidth == int.MaxValue) { element.HorizontalAlignment = HorizontalAlignment.Stretch; } else { element.HorizontalAlignment = HorizontalAlignment.Left; element.Width = iWidth; } element.SetValue(Grid.RowProperty, grid.RowDefinitions.Count - 1); element.SetValue(Grid.ColumnProperty, 1); grid.Children.Add(element); } } } //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Created Editors: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); OnEditorCreated?.Invoke(this, fGeneralHeight, 800); if(Details.Items[^1] is DynamicTabItem custom) { custom.Visibility = CustomGrid.Children.Count > 0 ? Visibility.Visible : Visibility.Collapsed; } //Logger.Send(LogType.Information, "DEG.CreateLayout", String.Format("Finalised: {0}", sw.ElapsedMilliseconds)); //sw.Stop(); } private Grid EnsureGrid(Dictionary grids, string caption) { if (grids.ContainsKey(caption)) return grids[caption]; // Create Editor, ScrollViewer and TabItem for Dynamic Editor var result = new Grid { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, //Background = new SolidColorBrush(Colors.Blue), Margin = new Thickness(0, 2.5, 0, 2.5) }; result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }); result.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); var scroll = new ScrollViewer { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, VerticalScrollBarVisibility = ScrollBarVisibility.Auto, Padding = new Thickness(2) }; scroll.Content = result; var border = new Border { BorderBrush = new SolidColorBrush(Colors.Gray), Background = new SolidColorBrush(Colors.White), BorderThickness = new Thickness(0.75) }; border.Child = scroll; var tab = new DynamicTabItem(); tab.Header = caption; tab.Content = border; if (Details.Items.Count == 0) Details.Items.Add(tab); else Details.Items.Insert(Details.Items.Count - 1, tab); grids[caption] = result; return result; } //List configuredpages = new List(); private void Details_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (bChanging || Details?.SelectedItem == null || e.OriginalSource != Details) return; bChanging = true; try { var tab = Details.SelectedItem as DynamicTabItem; if(tab is not null) { var page = tab.Content as IDynamicEditorPage; if (page is not null) { if (!page.Ready) using (new WaitCursor()) { OnLoadPage?.Invoke(page); } } else { if (!_loaded || e.RemovedItems.Count == 0 || e.AddedItems.Count == 0 || e.AddedItems?[0] == e.RemovedItems?[0]) return; //if (!configuredpages.Contains(tab)) //{ // ConfigureEditors(eds); // configuredpages.Add(tab); //} var selectedGrid = ((tab.Content as Border)?.Child as ScrollViewer)?.Content; var eds = editors .Where(x => x is BaseDynamicEditorControl control && control.Parent == selectedGrid) .Select(x => (BaseDynamicEditorControl)x); foreach (var ed in eds) { var editorvalue = ed.GetValue(); var entityvalue = OnGetPropertyValue?.Invoke(this, ed.ColumnName); if (!Equals(editorvalue, entityvalue)) { ed.Loaded = false; ed.SetValue(entityvalue); ed.Loaded = true; } } } OnSelectPage?.Invoke(tab, null); } } finally { bChanging = false; } } public void UnloadPages(bool saved) { if(Pages is not null) foreach (var page in Pages) if (page.Ready) OnUnloadPage?.Invoke(page, saved); } private void Lookup_OnUpdateOtherEditor(string columnname, object value) { var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname)); if (editor != null) CoreUtils.SetPropertyValue(editor, "Value", value); } private string FormatXML(string xml) { var result = ""; var mStream = new MemoryStream(); var writer = new XmlTextWriter(mStream, Encoding.Unicode); var document = new XmlDocument(); try { // Load the XmlDocument with the XML. document.LoadXml(xml); writer.Formatting = Formatting.Indented; // Write the XML into a formatting XmlTextWriter document.WriteContentTo(writer); writer.Flush(); mStream.Flush(); // Have to rewind the MemoryStream in order to read // its contents. mStream.Position = 0; // Read MemoryStream contents into a StreamReader. var sReader = new StreamReader(mStream); // Extract the text from the StreamReader. var formattedXml = sReader.ReadToEnd(); result = formattedXml; } catch (XmlException) { // Handle the exception } mStream.Close(); writer.Close(); return result; } public void EditLayout() { ClearPages(); //UnloadEditorValues(); var xaml = new GlobalConfiguration(_layoutname).Load().XAML; if (string.IsNullOrWhiteSpace(xaml)) { Details.Height = Details.ActualHeight; Details.Width = Details.ActualWidth; //xaml = XamlWriter.Save(GetParentWindow(Details)); xaml = XamlWriter.Save(Details); } xaml = FormatXML(xaml); var scripteditor = new ScriptEditor(xaml, SyntaxLanguage.XAML); if (scripteditor.ShowDialog() == true) { var layout = new ScreenLayout { XAML = scripteditor.Script }; new GlobalConfiguration(_layoutname).Save(layout); Content = null; if (!LoadLayout(layout.XAML)) if (!LoadLayout(xaml)) CreateLayout(); Details.ApplyTemplate(); Application.Current.Dispatcher.Invoke(() => { ConfigureEditors(); LoadEditorValues(); AddPages(); DoReconfigureEditors(); }, DispatcherPriority.Render); } } internal void ResetLayout() { new GlobalConfiguration(_layoutname).Delete(); ClearPages(); //UnloadEditorValues(); CreateLayout(); LoadEditorValues(); AddPages(); DoReconfigureEditors(); } private void LoadEditor(string columnname, object value) { } private void EditorValueChanged(IDynamicEditorControl sender, Dictionary values) { //Logger.Send(LogType.Information, "", string.Format("DynamicEditorGrid.EditorValueChanged({0})", values.Keys.Count)); var changededitors = new Dictionary(); foreach (var key in values.Keys) { var changedcolumns = OnEditorValueChanged?.Invoke(this, key, values[key]); if (changedcolumns != null) foreach (var (change, value) in changedcolumns) if (editors.Any(x => x.ColumnName.Equals(change)) && !changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName)) changededitors[change] = value; } if (changededitors.Any()) LoadEditorValues(changededitors); DoReconfigureEditors(); } private void LoadEditorValues(Dictionary? changededitors = null) { var columnnames = changededitors != null ? changededitors.Keys.ToArray() : editors.Select(x => x.ColumnName).ToArray(); foreach (var columnname in columnnames) { var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname)); if (editor == null) continue; var bLoaded = editor.Loaded; editor.Loaded = false; if (changededitors != null && changededitors.ContainsKey(columnname)) { CoreUtils.SetPropertyValue(editor, "Value", changededitors[columnname]); } else { var curvalue = OnGetPropertyValue?.Invoke(this, columnname); try { CoreUtils.SetPropertyValue(editor, "Value", curvalue); } catch (Exception e) { MessageBox.Show($"Unable to set editor value for {columnname} -> {curvalue}: {CoreUtils.FormatException(e)}"); } CoreUtils.SetPropertyValue(editor, "Changed", false); } editor.Loaded = bLoaded; editor.OnEditorValueChanged += EditorValueChanged; } } public virtual void DoReconfigureEditors() { ReconfigureEditors?.Invoke(this); } public void Load(string layoutname, DynamicEditorPages? pages = null) { _layoutname = layoutname; Pages = pages; //Stopwatch sw = new Stopwatch(); //sw.Start(); _columns = OnCustomiseColumns?.Invoke(this, null) ?? new DynamicGridColumns(); //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Columns: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); var layout = new GlobalConfiguration(_layoutname).Load(); //Logger.Send(LogType.Information, "DEG.Load", String.Format("Loaded Layout: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); if (!LoadLayout(layout.XAML)) CreateLayout(); //Logger.Send(LogType.Information, "DEG.Load", String.Format("Created Layout: {0}", sw.ElapsedMilliseconds)); //sw.Restart(); } protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { base.OnRenderSizeChanged(sizeInfo); foreach (var columnname in editors.Select(x => x.ColumnName).ToArray()) { var editor = editors.FirstOrDefault(x => x.ColumnName.Equals(columnname)); if(editor is not null) { editor.Loaded = true; } } } public bool Unload() { ClearPages(); var bChanged = false; foreach (var columnname in changes.Keys) { OnSetPropertyValue?.Invoke(this, columnname, changes[columnname]); bChanged = true; } return bChanged; } private void AddPages() { if (Pages != null) using (new WaitCursor()) { foreach (var page in Pages.OrderBy(x => x.Order()).ThenBy(x => x.Caption())) { var tab = new DynamicTabItem(); tab.Header = page.Caption(); tab.Content = page; Details.Items.Insert(Details.Items.Count - 1, tab); pagemap[page] = tab; if (PreloadPages) OnLoadPage?.Invoke(page); page.EditorGrid = this; } } //if (Details.Items.Count <= 2) // ((TabItem)Details.Items[0]).Visibility = Visibility.Collapsed; } private void ClearPages() { foreach (var page in pagemap.Keys) { var tab = pagemap[page]; tab.Content = null; Details.Items.Remove(tab); } pagemap.Clear(); //if (_pages != null) //{ // foreach (var page in _pages) // { // var tab = Details.Items.OfType().FirstOrDefault(x => x.Content.Equals(page)); // if (tab != null) // { // tab.Content = null; // Details.Items.Remove(tab); // } // } //} } } }