|  | @@ -9,7 +9,7 @@ namespace InABox.Core
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      public interface ILookupDefinition<TLookup> where TLookup : BaseObject, new()
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        Filter<TLookup> DefineFilter();
 | 
	
		
			
				|  |  | +        Filter<TLookup>? DefineFilter();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Columns<TLookup> DefineColumns();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -23,6 +23,12 @@ namespace InABox.Core
 | 
	
		
			
				|  |  |      public interface ILookupDefinition<TLookup, TEntity> where TLookup : Entity
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          Filter<TLookup> DefineFilter(TEntity[] items);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// Define the columns required for the <c>items</c> parameter of <see cref="DefineFilter(TEntity[])"/>.
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        /// <returns></returns>
 | 
	
		
			
				|  |  | +        Columns<TEntity> DefineFilterColumns();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public interface IStaticLookupDefinition<TEntity>
 | 
	
	
		
			
				|  | @@ -197,9 +203,9 @@ namespace InABox.Core
 | 
	
		
			
				|  |  |              var factory = _cache.GetFactory(TLookup, TEntity);
 | 
	
		
			
				|  |  |              if (factory != null)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | -                var filtertype = typeof(Filter<>).MakeGenericType(TLookup);
 | 
	
		
			
				|  |  | +                var filtertype = TResult.MakeGenericType(TLookup);
 | 
	
		
			
				|  |  |                  var method = factory.GetType().GetMethods().FirstOrDefault(m => 
 | 
	
		
			
				|  |  | -                    m.Name.Equals("DefineFilter") 
 | 
	
		
			
				|  |  | +                    m.Name.Equals(Method) 
 | 
	
		
			
				|  |  |                      && m.GetParameters().Any() 
 | 
	
		
			
				|  |  |                      && m.ReturnType == filtertype 
 | 
	
		
			
				|  |  |                      && m.GetParameters().First().ParameterType == items.GetType()
 | 
	
	
		
			
				|  | @@ -219,6 +225,30 @@ namespace InABox.Core
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return DoInvoke(TLookup, TResult, Method);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        private static object? DoInvoke(Type TLookup, Type TEntity, Type TResult, string Method)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var factory = _cache.GetFactory(TLookup, TEntity);
 | 
	
		
			
				|  |  | +            if (factory != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var method = factory.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(m => 
 | 
	
		
			
				|  |  | +                    m.Name.Split('.').Last().Equals(Method) // For explicit implementations, whose name is ILookupDefinition<TLookup,TEntity>.Method
 | 
	
		
			
				|  |  | +                    && !m.GetParameters().Any() 
 | 
	
		
			
				|  |  | +                    && m.ReturnType == TResult
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (method != null)
 | 
	
		
			
				|  |  | +                    try
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        return method.Invoke(factory, Array.Empty<object>());
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    catch (Exception e)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private static Dictionary<object, object> DoInvoke(Type TLookup, PropertyInfo property, string Method)
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -366,9 +396,36 @@ namespace InABox.Core
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              return DefineColumns(typeof(TLookup)) as Columns<TLookup>;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static IColumns DefineFilterColumns(Type TLookup, Type TEntity, IEnumerable items)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var result = DoInvoke(TLookup, TEntity, typeof(Columns<>).MakeGenericType(TEntity), "DefineFilterColumns") as IColumns;
 | 
	
		
			
				|  |  | +            if (result == null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var type = typeof(Columns<>).MakeGenericType(TLookup);
 | 
	
		
			
				|  |  | +                result = Activator.CreateInstance(type) as IColumns;
 | 
	
		
			
				|  |  | +                result = result.DefaultColumns();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return result;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static IColumns DefineFilterColumns<TEntity>(Type TLookup)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var result = DoInvoke(TLookup, typeof(TEntity), typeof(Columns<>).MakeGenericType(typeof(TEntity)), "DefineFilterColumns") as IColumns;
 | 
	
		
			
				|  |  | +            if (result == null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                result = Columns.Create(TLookup);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return result;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static Columns<TLookup> DefineFilterColumns<TEntity, TLookup>() where TEntity : Entity where TLookup : Entity
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return DefineFilterColumns<TEntity>(typeof(TLookup)) as Columns<TLookup>;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          #endregion
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          #region RequiredColumns
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          public static IColumns DefaultRequiredColumns(Type TLookup)
 |