How to create predicate dynamically
Asked Answered
I

3

13

Hi i want to create a list based on the search string using predicate expressions.

I have a list of type products contains different names.

List<products> list1 = new List<products>();

        list1.Add(new products("sowmya"));
        list1.Add(new products("Jane"));
        list1.Add(new products("John"));
        list1.Add(new products("kumar"));
        list1.Add(new products("ramya"));
        listBox1.ItemsSource = list1;

Now i want to filter the content based on user input.User will enter n no of strings with '+' as separator. After receiving the strings i will pass them to predicate object like this

 private void textBox1_KeyDown(object sender, KeyEventArgs e)
    {
        List<products> list2 = new List<products>();
        Expression<Func<products, bool>> predicate = PredicateBuilder.True<products>();
        if (e.Key == Key.Enter)
        {
            string Searchstring = textBox1.Text.ToString().Trim();
            string[] separator = new string[] { "+" };
            string[] SearchItems=Searchstring.Split(separator,StringSplitOptions.None);
            foreach (string str in SearchItems)
            {
                string temp = str;
                predicate =p => p.Name.Contains(temp.ToLower());                   
            }

            list2 = list1.AsQueryable().Where(predicate).ToList();
            listBox1.ItemsSource = list2;
        }
    }

If i enter more than one string(sowmya+jane+john) its giving only the last string(john) result but i want a list of all matching strings

Please answer this question because i'm trying this but i couldn't get the result.

Please do some help thanks.

Ironsmith answered 17/6, 2011 at 9:28 Comment(1)
dup: #845559Sightread
S
27

Initialize the predicate as false

Expression<Func<products, bool>> predicate = PredicateBuilder.False<products>();

You need to combine the predicates using Or

foreach (string str in SearchItems)
{
    string temp = str;
    predicate = predicate.Or(p => p.NameToLower().Contains(temp.ToLower()));                   
}

Source for predicate builder here. It is part of LINQKit

Code, in case link goes

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

public static class PredicateBuilder
{
  public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  public static Expression<Func<T, bool>> False<T> () { return f => false; }

  public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
                                                      Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  }

  public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                       Expression<Func<T, bool>> expr2)
  {
    var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
    return Expression.Lambda<Func<T, bool>>
          (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  }
}
Seymourseys answered 17/6, 2011 at 9:40 Comment(5)
If i use And to combine predicates its giving all the list items but not the matching string resultIronsmith
@Ironsmith updated my answer. you need to use temp not str inside the predicateSeymourseys
Hey Eranga thank you soooo much its working fine. Really you helped meIronsmith
Is this predicatebuilder the same to this article albahari.com/nutshell/predicatebuilder.aspx?Chuddar
PredicateBuilder?Oblast
C
1

As I am not sure that predicate instance has an And method, I suggest you use this code:

var list = list1.AsQueryable();
foreach (string str in SearchItems)
{
     list = list.Where(p => p.Name.ToLower().Contains(str.ToLower()));
}
listBox1.ItemsSource = list.ToList();
Cabochon answered 17/6, 2011 at 9:50 Comment(4)
if i use this code its giving only one string result but if i enter two strings its not giving any result.Please find the solution.I need it.Ironsmith
that might be because of the first .ToLower() I just added. if not make sure your Name property really contains both of the strings you search forCabochon
same issue again giving the last string result only.Ya i'm sure The "Name" property contains both the stringsIronsmith
you should check if you have copied and pasted the code correctly then.Cabochon
H
1

You don't have to build a predicate here. You can try something like this

List<products> list1 = new List<products>();

list1.Add(new products("sowmya"));
list1.Add(new products("Jane"));
list1.Add(new products("John"));
list1.Add(new products("kumar"));
list1.Add(new products("ramya"));

string input = "aaa+kuma+ram";
List<string> searchStrings =
    input.Split(new string[] { "+" }, StringSplitOptions.None)
    .Select(s => s.ToLower())
    .ToList();

List<products> list2 = (
    from p in list1
    where searchStrings.Any(s => p.Name.Contains(s))
    select p).ToList();

list2 will contain "kumar" and "ramya".

Hamadryad answered 17/6, 2011 at 10:16 Comment(4)
Thank u and this will work and working also i knew that but i need to construct it by using predicate only please help meIronsmith
@Ironsmith then you should try what Eranga suggests.Hamadryad
Sorry, but this is just the classical way of using predicates in LINQ. There's nothing dynamic here.Cohleen
The OP had a goal, he thought he needed dynamic predicates to reach that goal. I showed how to reach it without dynamic predicates.Hamadryad

© 2022 - 2024 — McMap. All rights reserved.