using System; using System.Collections.Generic; using System.Linq; using InABox.Clients; using InABox.Core; namespace InABox.DynamicGrid { public interface IDynamicEditorHost { /// /// A list of columns which are defined for this editor; from this are loaded the additional columns for lookups. A useful default is just /// to call , if a singular type for the editor is well-defined. /// /// /// I'm still not sure whether this one is actually a good idea, but it seems to be how the editors have functioned for a while. My reasoning is that /// if the lookup defines a column to be loaded, but it doesn't get loaded because it is not in this list, then we would have broken functionality. /// IEnumerable Columns { get; } /// /// Loads into all columns that start with the same prefix as ; e.g, when taking a /// lookup defined for column EntityLink.ID, will contain all EntityLink.* except EntityLink.ID. /// /// This essentially gives us the other columns we need to load from the database for lookups. /// See for the canonical implementation. /// /// /// This is dumb; we don't want it, because the presence of kinda makes it redundant. /// /// The column to use the prefix of. /// The dictionary into which the columns will be loaded, in the form "FieldName": "EntityLink.FieldName" void LoadColumns(string column, Dictionary columns); /// /// In most cases, calls , and I think this should explain what this method does. Provide a method that /// doesn't do this if you like breaking things (or if you need to provide a filter that differs from the standard lookup; just make sure that you /// check , and use the function if not the type you want). /// /// The T in . /// A filter (or , being synonymous with ). IFilter? DefineFilter(Type type); /// /// Trigger the loading of the lookup values; the canonical implementation calls , /// and calls (either sync/async) when the values are loaded. /// /// The editor to load the lookups for. void LoadLookups(ILookupEditorControl editor); /// /// Get a document for a given filename. /// /// /// The usual implementation will go through the interface. /// /// The filename of the document. /// The document with the right filename, or if not found. Document? FindDocument(string filename) { return new Client().Load(new Filter(x => x.FileName).IsEqualTo(filename)).FirstOrDefault(); } /// /// Get a document for a given ID. /// /// /// The usual implementation will go through the interface. /// /// The ID of the document. /// The document, or if not found. Document? GetDocument(Guid id) { return new Client().Load(new Filter(x => x.ID).IsEqualTo(id)).FirstOrDefault(); } /// /// Saves a document. /// /// /// The usual implementation will go through the interface. /// /// The document to save. void SaveDocument(Document document) { new Client().Save(document, "Updated by Editor"); } /// /// Returns a list of the currently edited items; may be an empty array. /// /// This should probably always be a []. /// /// The items being edited. object?[] GetItems(); /// /// Um... I'm really not sure; achieves the same function as - if you know what that does, good job. /// /// /// I think you should be fine to just return .Editor, as defined by . /// /// The column to get the editor of. /// The editor, or if it doesn't exist. BaseEditor? GetEditor(DynamicGridColumn column); } public class DefaultDynamicEditorHost : IDynamicEditorHost where T : BaseObject { public virtual T[]? Items { get; set; } public IEnumerable Columns => new DynamicGridColumns().ExtractColumns(typeof(T)); public virtual IFilter? DefineFilter(Type type) => LookupFactory.DefineFilter(Items ?? Enumerable.Empty(), type); public BaseEditor? GetEditor(DynamicGridColumn column) => column.Editor.CloneEditor(); public object?[] GetItems() => Items ?? Array.Empty(); public void LoadColumns(string column, Dictionary columns) { columns.Clear(); var comps = column.Split('.').ToList(); comps.RemoveAt(comps.Count - 1); var prefix = string.Format("{0}.", string.Join(".", comps)); var cols = Columns.Where(x => !x.ColumnName.Equals(column) && x.ColumnName.StartsWith(prefix)); foreach (var col in cols) columns[col.ColumnName.Replace(prefix, "")] = col.ColumnName; } public void LoadLookups(ILookupEditorControl sender) { var editor = sender.EditorDefinition as ILookupEditor; var colname = sender.ColumnName; var values = editor.Values(colname, Items); sender.LoadLookups(values); } } }