【问题标题】:Create a search form dynamically in run-time based on <T> properties基于 <T> 属性在运行时动态创建搜索表单
【发布时间】:2013-06-16 07:56:38
【问题描述】:

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

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

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

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

搜索表单将是这样的:

对于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. 如何获取&lt;T&gt; 类型的所有属性?

  2. 我怎样才能动态创建这个predicate(附加条件到 彼此动态)?

【问题讨论】:

    标签: c# generics runtime func


    【解决方案1】:

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

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

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

    拥有一个应该由您的所有Ts 实现的接口。比如:

     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
    {
       ....
    }
    

    还有波科:

    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.
          }  
       }
    

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

    【讨论】:

    • 谢谢,但我不想像你说的那样从 Order 获得修复谓词,我想根据最终用户的输入制作谓词
    • @Masoud 这没什么大不了的。而不是Func&lt;bool&gt;,取Func&lt;string, decimal, decimal, bool&gt;
    • 但如果用户没有在 Orderweight TextBox 中输入任何值,我不想在我的谓词中包含 OrderWeight 以及。
    • @Masoud 我的目的是给你一个(替代)想法如何解决这个问题,而不是一个非常精确、经过测试、功能强大的库:) 你当然可以根据你想要的方式构建它.我的方法确实提供了那种定制的灵活性。在您的情况下,您可以检查 OrderWeight 是否为零并在 Order 类的谓词内退出。如果 0 是有效值,则让您的 func 为 Func&lt;TextBox, TextBox, TextBox, bool&gt; 并检查文本框值,依此类推。如果你愿意,你甚至可以让它们都通用。最后,这种方法更好设计并且应该更快
    【解决方案2】:

    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));
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      相关资源
      最近更新 更多