基于<t>属性</t>在运行时动态创建搜索表单

时间:2013-06-16 07:56:39

标签: c# generics runtime func

我正在WindowsForm应用程序中创建一个搜索表单:

public partial class SearchForm<T>()
{
   ....
}

我希望在运行时基于T属性类型创建一些控件, 例如,如果TOrder

public class Order
{
   public string OrderNumber {get; set;}
   public decimal OrderWeight {get; set;}
}

搜索表单将是这样的:

enter image description here

我希望string属性有一个TextBox,对于数字属性,有2 Control(一个用于From,另一个用于To)

我还希望将用户选择的条件放在predicate变量中:

Func<T, bool> predicate;

例如

predicate = t => t.OrderNumber.Contains("ORDER-01") && 
                 t.OrderWeight >= 100 &&
                 t.OrderWeight <= 200;

我的问题是

  1. 如何获取<T>类型的所有属性?

  2. 如何动态创建此predicate(将条件附加到 彼此动态地)?

2 个答案:

答案 0 :(得分:1)

要获取类型的属性,您可以依赖反射。见How to get the list of properties of a class?

从那里你可以使用表达式树来构建动态谓词。见How do I dynamically create an Expression<Func<MyClass, bool>> predicate?

但我建议采用更简单(但涉及更多打字)的方法。

有一个应由所有T实现的界面。类似的东西:

 public interface Searchable
 {
      IEnumerable<ParamInfo> Params { get; }
      Func<string, decimal, decimal, bool> Predicate { get; }
 }

ParamInfo班级:

public class ParamInfo
{
    public string LabelText { get; private set; }

    public Type EditControl { get; private set; }

    public Type DataType { get; private set; }

    public object DefaultValue { get; private set; }

    public bool Required { get; private set; }

    //etc. basically a good info class the decides how to draw gui
}

您的搜索表单可以

public partial class SearchForm<T> where T : Searchable
{
   ....
}

和poco:

public class Order : Searchable
{
   public string OrderNumber {get; set;}
   public decimal OrderWeight {get; set;}

   public IEnumerable<ParamInfo> Params 
   {  
      get 
      { 
          return new List<ParamInfo> 
          {
              new ParamInfo(typeof(TextBox), typeof(string), "Enter value", true),
              new ParamInfo(typeof(TextBox), typeof(decimal), 0, true),
              new ParamInfo(typeof(TextBox), typeof(decimal), 0, true)
          }
      }  
   }

   public Func<string, decimal, decimal, bool> Predicate
   {  
      get 
      { 
          return (s, d1, d2) => OrderNumber.Contains(s) 
                             && OrderWeight >= d1 
                             && OrderWeight <= d2; //and so on, u get the idea.
      }  
   }

这提供了更多的灵活性。您可以直接将谓词附加到每个ParamInfo中的T类,而不是动态构建谓词 。这是我们在您的项目中使用的东西。

答案 1 :(得分:1)

1)通过反射获取有关Properties的信息,使用PropertyType按类型

进行过滤
PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
return properties.Where(p => p.PropertyType == typeof(string));

2)由于predicate的返回类型为bool,获得所需结果的简单方法是:

public Func<T, bool> AllTrue<T>(IEnumerable<Func<T, bool>> predicates)
{
    return t => predicates.All(p => p(t));
}