using InABox.Core; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Document = InABox.Core.Document; namespace InABox.DynamicGrid { /// /// Interaction logic for EmbeddedDynamicEditorForm.xaml /// public partial class EmbeddedDynamicEditorForm : UserControl, IDynamicEditorForm { public delegate void OKEvent(); public delegate void CancelEvent(); public DynamicEditorPages Pages { get; private set; } = new(); private BaseObject[] _items; public BaseObject[] Items { get => _items; set { _items = value; DynamicEditorFormModel.Slug = Items != null ? Items.Any() ? Items.First().GetType().EntityName().Split('.').Last() : "" : ""; Editor.Load(Pages); } } public bool ReadOnly { get; set; } public static readonly DependencyProperty ButtonsVisibleProperty = DependencyProperty.Register( nameof(ButtonsVisible), typeof(bool), typeof(EmbeddedDynamicEditorForm), new UIPropertyMetadata(true) ); public bool ButtonsVisible { get => (bool)GetValue(ButtonsVisibleProperty); set { SetValue(ButtonsVisibleProperty, value); UpdateButtonsRowVisibility(); } } private void UpdateButtonsRowVisibility() { ButtonRow.Height = ButtonsVisible ? new GridLength(40, GridUnitType.Pixel) : new GridLength(0, GridUnitType.Pixel); } public static readonly DependencyProperty TabsVisibleProperty = DependencyProperty.Register( nameof(TabsVisible), typeof(bool), typeof(EmbeddedDynamicEditorForm), new UIPropertyMetadata(true) ); public bool TabsVisible { get => (bool)GetValue(TabsVisibleProperty); set { SetValue(TabsVisibleProperty, value); UpdateTabsVisibility(); } } private void UpdateTabsVisibility() { Editor.TabStripVisible = TabsVisible; } #region Events public event OnValidateData? OnValidateData; public event OnCustomiseColumns? OnCustomiseColumns; public event OnDefineFilter? OnDefineFilter; public event OnDefineLookup? OnDefineLookups; public event DefineEditorEventHandler? OnDefineEditor; public event OnFormCustomiseEditor? OnFormCustomiseEditor; public event OnReconfigureEditors? OnReconfigureEditors; public event EditorValueChangedHandler? OnEditorValueChanged; public event OnAfterEditorValueChanged? OnAfterEditorValueChanged; public event IDynamicEditorForm.GetDocumentEvent? OnGetDocument; public event IDynamicEditorForm.FindDocumentEvent? OnFindDocument; public event IDynamicEditorForm.SaveDocumentEvent? OnSaveDocument; public event OnSelectPage? OnSelectPage; public event DynamicGridSaveEvent? OnSaveItem; public event DynamicEditorGrid.EditorCreatedHandler? OnEditorCreated; public event OKEvent? OnOK; public event CancelEvent? OnCancel; #endregion public EmbeddedDynamicEditorForm() { InitializeComponent(); } public override void OnApplyTemplate() { base.OnApplyTemplate(); UpdateButtonsRowVisibility(); UpdateTabsVisibility(); } public EmbeddedDynamicEditorForm(Type type, DynamicEditorPages? pages = null, DynamicEditorButtons? buttons = null, Func? PageDataHandler = null, bool PreloadPages = false): this() { Setup(type, pages, buttons, PageDataHandler, PreloadPages); } public void Setup(Type type, DynamicEditorPages? pages = null, DynamicEditorButtons? buttons = null, Func? PageDataHandler = null, bool PreloadPages = false) { ReadOnly = false; //this.Loaded += new RoutedEventHandler(ConfigureSystemMenu); Editor.UnderlyingType = type; Editor.OnCustomiseColumns += Editor_OnCustomiseColumns; Editor.OnDefineFilter += editor => OnDefineFilter?.Invoke(editor); Editor.OnEditorCreated += Editor_OnEditorCreated; Editor.OnLoadPage += page => { page.Load(Items.First(), PageDataHandler); }; Editor.OnSelectPage += (tab, items) => { OnSelectPage?.Invoke(tab, items); }; Editor.PreloadPages = PreloadPages; Editor.OnUnloadPage += (page, saved) => { if (!saved) page.BeforeSave(Items.First()); else page.AfterSave(Items.First()); }; //Editor.OnGetPropertyInfo += (o, c) => { return CoreUtils.GetProperty(_item.GetType(), c); }; Editor.OnAfterEditorValueChanged += (g, n) => { return OnAfterEditorValueChanged?.Invoke(g, n); }; Editor.OnReconfigureEditors += g => { OnReconfigureEditors?.Invoke(g); }; Editor.OnGetEditor += c => { if (_items != null && _items.Any()) { var property = DatabaseSchema.Property(type, c.ColumnName); if (property == null) return new NullEditor(); if (property.Editor is NullEditor) return property.Editor; BaseEditor editor; if (property is CustomProperty) { editor = property.Editor.CloneEditor(); } else { editor = OnDefineEditor?.Invoke(_items[0], c) ?? c.Editor.CloneEditor(); var propEditor = property.Editor; editor.Page = propEditor.Page; editor.Caption = propEditor.Caption; } //defaultEditor.EditorSequence //EditorUtils.GetPropertyEditor(type, property, defaultEditor); /*BaseEditor editor = new NullEditor(); var caption = ""; var page = ""; try { var comps = c.ColumnName.Split('.'); for (var i = 0; i < comps.Length; i++) { var column = string.Join(".", comps.Take(i + 1)); var prop = CoreUtils.GetProperty(type, column); if (column.Equals(c.ColumnName)) { if (OnDefineEditor != null) editor = OnDefineEditor(_items[0], c); else editor = c.Editor != null ? c.Editor : new NullEditor(); } else { var pedit = prop.GetEditor(); if (pedit is NullEditor) return pedit; } editor = editor == null ? new NullEditor() : editor.Clone() as BaseEditor; var capattr = prop.GetCustomAttribute(); var subcap = capattr != null ? capattr.Text : comps[i]; var path = capattr != null ? capattr.IncludePath : true; if (!string.IsNullOrWhiteSpace(subcap)) caption = string.IsNullOrWhiteSpace(caption) || path == false ? subcap : string.Format("{0} {1}", caption, subcap); if (string.IsNullOrWhiteSpace(page)) { var pageattr = prop.GetCustomAttribute(); if (pageattr != null) page = pageattr.Page; } } editor.Caption = caption; editor.Page = page; } catch (Exception e) { var dmprop = DatabaseSchema.Property(_items[0].GetType(), c.ColumnName); if (dmprop is CustomProperty) { editor = dmprop.Editor.Clone() as BaseEditor; editor.Caption = dmprop.Caption; editor.Page = string.IsNullOrWhiteSpace(dmprop.Page) ? "Custom Fields" : dmprop.Page; } }*/ if (ReadOnly && editor.Editable.Equals(Editable.Enabled)) editor.Editable = Editable.Disabled; return editor; } return new NullEditor(); }; Editor.OnGridCustomiseEditor += (sender, column, editor) => OnFormCustomiseEditor?.Invoke(this, Items, column, editor); Editor.OnGetSequence += c => CoreUtils.GetPropertySequence(_items.First().GetType(), c.ColumnName); Editor.OnGetPropertyValue += (o, c) => { if (!_items.Any()) return null; object? result; try { result = CoreUtils.GetPropertyValue(_items.First(), c); } catch { result = _items.First().UserProperties.ContainsKey(c) ? _items.First().UserProperties[c] : null; } if (result == null) return null; foreach (var _item in _items) { object? curvalue; try { curvalue = CoreUtils.GetPropertyValue(_item, c); } catch { curvalue = _item.UserProperties.ContainsKey(c) ? _item.UserProperties[c] : null; } if (curvalue == null) return null; if (!curvalue.Equals(result)) return null; } return result; }; Editor.OnSetPropertyValue += (o, c, v) => { foreach (var _item in _items) if (_item.UserProperties.ContainsKey(c)) _item.UserProperties[c] = v; else CoreUtils.SetPropertyValue(_item, c, v); }; Editor.OnEditorValueChanged += EditorValueChanged; Editor.OnDefineLookups += sender => { OnDefineLookups?.Invoke(sender); }; Editor.OnGetDocument += id => { return OnGetDocument?.Invoke(id); }; Editor.OnSaveDocument += doc => { OnSaveDocument?.Invoke(doc); }; Editor.OnFindDocument += file => { return OnFindDocument?.Invoke(file); }; Editor.GetItems += () => _items; Pages = pages ?? new DynamicEditorPages(); if (Pages == null || Pages.Count == 0) Editor.Margin = new Thickness(5, 5, 5, 0); Buttons.Children.Clear(); if (buttons != null) foreach (var button in buttons) { var btn = new Button(); UpdateButton(btn, button.Image, button.Name); btn.Tag = button; btn.Margin = new Thickness(5, 5, 0, 5); btn.Padding = new Thickness(5, 0, 5, 0); btn.Click += Btn_Click; Buttons.Children.Add(btn); button.Button = btn; button.Form = this; } } public void UnloadEditorPages(bool saved) { Editor.UnloadPages(saved); } protected void UpdateButton(Button button, BitmapImage? image, string text) { var stackPnl = new StackPanel(); stackPnl.Orientation = Orientation.Horizontal; //stackPnl.Margin = new Thickness(2); if (image != null) { var img = new Image(); img.Source = image; img.Margin = new Thickness(2); stackPnl.Children.Add(img); } if (!string.IsNullOrEmpty(text)) { var lbl = new Label(); lbl.Content = text; lbl.VerticalAlignment = VerticalAlignment.Stretch; lbl.VerticalContentAlignment = VerticalAlignment.Center; lbl.Margin = new Thickness(2, 0, 5, 0); stackPnl.Children.Add(lbl); } button.Content = stackPnl; } private Dictionary EditorValueChanged(object sender, string name, object value) { if (OnEditorValueChanged != null) return OnEditorValueChanged(sender, name, value); return DynamicGridUtils.UpdateEditorValue(_items, name, value); } private void Editor_OnEditorCreated(object sender, double height, double width) { OnEditorCreated?.Invoke(sender, height, width); Editor.VerticalAlignment = VerticalAlignment.Stretch; Editor.HorizontalAlignment = HorizontalAlignment.Stretch; OKButton.IsEnabled = !ReadOnly; } private void Editor_OnCustomiseColumns(object sender, DynamicGridColumns columns) { columns.Clear(); if (_items != null && _items.Any()) columns.ExtractColumns(_items.First().GetType()); OnCustomiseColumns?.Invoke(this, columns); } private void Btn_Click(object sender, RoutedEventArgs e) { var button = (Button)sender; var deb = (DynamicEditorButton)button.Tag; deb.Click(); } private void OKButton_Click(object sender, RoutedEventArgs e) { var errors = OnValidateData?.Invoke(this, Items); if (errors != null && errors.Any()) { MessageBox.Show( string.Format("The following errors have been found with your data!\nPlease correct them and try again.\n\n- {0}", string.Join("\n- ", errors)), "Validation Error"); return; } OnOK?.Invoke(); // Don't Commit the changes here, because we want to refer back to thos changes when we save the item // to trigger specific processes in the database //Close(); } private void CancelButton_Click(object sender, RoutedEventArgs e) { // However, if we cancel the edits, then we can safely revert the items back to their original (loaded) state foreach (var item in _items) item.CancelChanges(); OnCancel?.Invoke(); //Close(); } public void SaveItem(CancelEventArgs e) { OnSaveItem?.Invoke(this, e); } public bool TryFindEditor(string columnname, [NotNullWhen(true)] out IDynamicEditorControl? editor) { return Editor.TryFindEditor(columnname, out editor); } public IDynamicEditorControl FindEditor(string columnname) { return Editor.FindEditor(columnname); } public object? GetEditorValue(string columnName) => FindEditor(columnName).GetValue(columnName); public void SetEditorValue(string columnName, object? value) => FindEditor(columnName).SetValue(columnName, value); public void SetLayoutType() where T : DynamicEditorGridLayout => Editor.SetLayoutType(); //public void EditLayout() => Editor.EditLayout(); //public void ResetLayout() => Editor.ResetLayout(); } }