1

I'm creating a search form in my WindowsForm application:

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

i want in run-time create some Controls based on T property types, for example if T is Order:

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

the search form will be something like this:

enter image description here

for string properties i want have one TextBox, and for numeric properties, 2 Control(one for From, and another for To)

also i want to put the user selected conditions in a predicate variable:

Func<T, bool> predicate;

for example

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

my questions are

  1. how can i get all properties of a <T> type?

  2. how can i create this predicate dynamically(attach conditions to each other dynamically)?

Masoud
  • 8,020
  • 12
  • 62
  • 123

2 Answers2

1

To get the properties of a type, you could rely on reflection. See How to get the list of properties of a class?

And from there you can using expression trees to build dynamic predicate. See How do I dynamically create an Expression<Func<MyClass, bool>> predicate?

But I would suggest having a simpler (but involves more typing) approach.

Have an interface that should be implemented by all your Ts. Something like:

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

And a ParamInfo class:

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
}

Your search form can then be

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

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

This gives a lot more flexibility. Instead of building predicate dynamically, you can directly attach predicates to ParamInfo class in each of your Ts. This is something we use in your project.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • thanks, but i don't want to get a fix predicate from Order as yo said, i want to make predicate based on end user inputs – Masoud Jun 16 '13 at 08:52
  • @Masoud it isn't a big deal. Instead of `Func`, take `Func` – nawfal Jun 16 '13 at 08:59
  • but if user didn't input any value to Orderweight TextBox i don't want include OrderWeight in my predicate and also on. – Masoud Jun 16 '13 at 09:27
  • 1
    @Masoud my intention was to give you an (alternate) idea how to tackle this, not a very precise, tested, ever functional library :) You can of course build on that according to how you want. It is indeed that kind of flexibility to customize that my approach gives. In your case, you can check if OrderWeight is zero and quit inside the predicate in Order class. If 0 is a valid value, then let your func be `Func` and check for textbox value, and so on. You can even have them all generic if you want. In the end this approach is better *designed* & should be faster – nawfal Jun 16 '13 at 09:33
1

1) Get infofmation about Properties via reflection, use PropertyType to filter by type

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

2) As the return type of your predicate is bool, the simple way to get the desired result is:

public Func<T, bool> AllTrue<T>(IEnumerable<Func<T, bool>> predicates)
{
    return t => predicates.All(p => p(t));
}
lisp
  • 4,138
  • 2
  • 26
  • 43