Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Visual Expression Builder for Dynamic Linq

, 2 Feb 2012
Let your users create their own Linq filters with this MVVM WPF tool you can include in your application
DynamicLinqExpressionBuilder.zip
.svn
all-wcprops
dir-prop-base
entries
prop-base
ClassDiagram.png.svn-base
ScreenShot.png.svn-base
props
text-base
ClassDiagram.png.svn-base
ClassDiagram1.cd.svn-base
DoNotFilterOnAttribute.cs.svn-base
DynamicLinqExpressionBuilder.csproj.svn-base
DynamicLinqExpressionBuilder.sln.svn-base
DynamicLinqUserControl.xaml.cs.svn-base
DynamicLinqUserControl.xaml.svn-base
ExpressionList.cs.svn-base
ScreenShot.png.svn-base
tmp
prop-base
props
text-base
bin
Debug
DynamicLinqExpressionBuilder.dll
ClassDiagram.png
ClassDiagram1.cd
Properties
.svn
all-wcprops
entries
prop-base
props
text-base
AssemblyInfo.cs.svn-base
tmp
prop-base
props
text-base
ScreenShot.png
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Linq.Expressions;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Controls;

namespace ChabadOnCampus.DynamicLinq
{
    public class ExpressionVM: INotifyPropertyChanged
    {

        IEnumerable<PropertyInfo> _AvailableProperties;
        public IEnumerable<PropertyInfo> AvailableProperties
        {
            get { return _AvailableProperties; }
            set
            {
                _AvailableProperties = value;
                OnPropertyChanged("AvailableProperties");
            }
        }

        public Array AvailableCompareOperators
        {
            get 
            {
                if (PropertyType == typeof(string))
                {
                    return new ComparisonOperators[] { ComparisonOperators.Equal, ComparisonOperators.NotEqual, ComparisonOperators.Contains };
                }
                else
                {
                    var operators = from o in Enum.GetValues(typeof(ComparisonOperators)).Cast<ComparisonOperators>()
                                    where o != ComparisonOperators.Contains // exclude "Contains" as only works for String
                                    select o;
                    return operators.ToArray();
                }
            }
        }
        public Array AvailableCombinationOperators
        {
            get { return Enum.GetValues(typeof(CombinationOperators)); }
        }

        private Type _ObjectType;
	    public Type ObjectType
	    {
		    get { return _ObjectType;}
            set { 
                _ObjectType = value;
                if (value == null)
                {
                    AvailableProperties = null;
                }
                else
                {
                    AvailableProperties = from p in value.GetProperties()
                                          where GetSupportedTypes().Contains(p.PropertyType) &&
                                          p.GetCustomAttributes(typeof(DoNotFilterOnAttribute), true).Length == 0 // in other words, where attribute is NOT applied
                                          select p;
                }
                OnPropertyChanged("ObjectType");
            }
	    }
	
        private ComparisonOperators _CompareOperator = ComparisonOperators.Equal;
        public ComparisonOperators CompareOperator
        {
            get { return _CompareOperator; }
            set { _CompareOperator = value; OnPropertyChanged("CompareOperator"); }
        }

        private CombinationOperators _CombineOperator = CombinationOperators.And;
        public CombinationOperators CombineOperator
        {
            get { return _CombineOperator; }
            set { _CombineOperator = value; OnPropertyChanged("CombineOperator"); }
        }

        private PropertyInfo _PropertyInfo;
        public PropertyInfo PropertyInfo
        {
            get { return _PropertyInfo; }
            set {
                _PropertyInfo = value;
                OnPropertyChanged("PropertyInfo");
                OnPropertyChanged("PropertyType");
                OnPropertyChanged("PropertyName");
                OnPropertyChanged("AvailableCompareOperators");
                OnPropertyChanged("Value2");
                OnPropertyChanged("ValueControl");
            }
        }
 	    public Type PropertyType
	    {
            get { return PropertyInfo == null? typeof(string) : PropertyInfo.PropertyType; }
	    }
        public string PropertyName
        {
            get { return PropertyInfo == null ? null : PropertyInfo.Name; }
        }

        public dynamic Value
        {
            get { return Value2.Value; }
            set
            {
                if (!Object.Equals(Value2.Value, value))
                {
                    Value2.Value = value;
                    OnPropertyChanged("Value");
                }
            }
        }
        private object _Value2;
        public dynamic Value2
        {
            get {
                Type specificType = typeof(Variant<>).MakeGenericType(new Type[] { PropertyType });
                if(_Value2 == null || _Value2.GetType() != specificType)
                {
                    _Value2 = Activator.CreateInstance(specificType);
                }
                return _Value2;
            }
        }

        public Control ValueControl 
        {
            get
            {
                Binding binding = new Binding("Value2.Value");
                binding.Source = this;

                if (PropertyType == typeof(DateTime) || PropertyType == typeof(DateTime?))
                {
                    DatePicker dp = new DatePicker();
                    dp.SetBinding(DatePicker.SelectedDateProperty, binding);
                    return dp;
                }
                else
                {
                    TextBox tb = new TextBox();
                    tb.SetBinding(TextBox.TextProperty, binding);
                    return tb;
                }
            }
        }

        public static object CreateGeneric(Type generic, Type innerType, params object[] args)
        {
            System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
            return Activator.CreateInstance(specificType, args);
        }
        public LambdaExpression MakeExpression(ParameterExpression paramExpr = null)
        {
            if(paramExpr == null) paramExpr = Expression.Parameter(ObjectType, "left");
            
            var callExpr = Expression.MakeMemberAccess(paramExpr, PropertyInfo);
            var valueExpr = Expression.Constant(Value, PropertyType);
            Expression expr;

            if (CompareOperator == ComparisonOperators.Contains)
            {
                expr = Expression.Call(callExpr, PropertyType.GetMethod("Contains"), valueExpr);
            }
            else
            {
                expr = Expression.MakeBinary((ExpressionType)CompareOperator, callExpr, valueExpr);
            }
            
            return Expression.Lambda( expr, paramExpr);
        }

        public static IEnumerable<Type> GetSupportedTypes()
        {
            return new Type[] {typeof(DateTime), typeof(DateTime?),
                                          typeof(long), typeof(long?), typeof(short), typeof(short?), 
                                          typeof(ulong), typeof(ulong?), typeof(ushort), typeof(ushort?), 
                                          typeof(Single), typeof(Single?), typeof(Double), typeof(Double?), 
                                          typeof(Decimal), typeof(Decimal?), typeof(Boolean), typeof(Boolean?), 
                                          typeof(int), typeof(int?), typeof(uint), typeof(uint), 
                                          typeof(string)};
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string value)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(value));
        }
    }

    public class ExpressionList: ObservableCollection<ExpressionVM>
    {

        private Type _Type;
        public Type Type
        {
            get { return _Type; }
            set {
                _Type = value;
                
                foreach(ExpressionVM c in this)
                {
                    //c.AvailableProperties = props.ToArray().Clone() as PropertyInfo[];
                    c.ObjectType = value;
                }
            }
        }

        protected override void InsertItem(int index, ExpressionVM item)
        {
            base.InsertItem(index, item);
            if (item.ObjectType == null) item.ObjectType = Type;
        }

        public LambdaExpression CompleteExpression
        {
            get
            {
                var paramExp = Expression.Parameter(Type, "left");
                if (this.Count == 0) return Expression.Lambda(Expression.Constant(true), paramExp);
                LambdaExpression lambda1 = this.First().MakeExpression(paramExp);
                var ret = lambda1.Body;
                foreach (var c in this.Skip(1))
                    ret = Expression.MakeBinary((ExpressionType)c.CombineOperator, ret, c.MakeExpression(paramExp).Body);
                return Expression.Lambda(ret, paramExp);
            }
        }

        public Expression<Func<T, bool>> GetCompleteExpression<T>()
        {
            return this.CompleteExpression as Expression<Func<T, bool>>;
        }
    }

    public enum ComparisonOperators
    {
            Equal = ExpressionType.Equal,
            NotEqual = ExpressionType.NotEqual,
            LessThan = ExpressionType.LessThan,
            GreaterThan = ExpressionType.GreaterThan,
            LessThanOrEqual = ExpressionType.LessThanOrEqual,
            GreaterThanOrEqual = ExpressionType.GreaterThanOrEqual,
            Contains
    }

    public enum CombinationOperators
    {
            Or = ExpressionType.Or,
            And = ExpressionType.And,
            Xor = ExpressionType.ExclusiveOr,
    }

    public struct Variant<T>
    {
        public T Value { get; set; }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rabb Moshe Plotkin

United States United States
Co-director of Chabad Student Center @ SUNY New Paltz
Lecturer of Computer Science @ SUNY New Paltz
Follow on   Twitter

| Advertise | Privacy | Mobile
Web01 | 2.8.140921.1 | Last Updated 2 Feb 2012
Article Copyright 2010 by Rabb Moshe Plotkin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid