2013-08-27 11 views
1

我試着去過濾器適用於WPF DataGrid中和過濾器屬性需要一個謂語方法返回一個謂語< T >(其中T是僅在運行時知道)

例如:

dataGrid1.Filter = p => p.A_Field_Table1.Contains(textBox.Text); 

但我的數據網格正在填充反射,所以我只知道運行時數據網格內的對象的類型。

然後我創建的動態生成謂詞< T>的方法:

public static Predicate<T> GetPredicate<T>(string column, string valueP, T objSource, string table) 
    { 
     Type itemType = typeof(T); 

     ParameterExpression predParam = Expression.Parameter(itemType, "p"); 
     Expression left = Expression.Property(predParam, itemType.GetProperty("A_" + column+ "_" + table)); 
     var valueStr= Expression.Constant(valueP); 
     var typeOfStr = valueStr.Type; 
     var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) }); 
     var call = Expression.Call(left, containsMethod, valueStr); 
     Func< T, bool > function = (Func< T, bool >)Expression.Lambda(call, new[] { predParam }).Compile(); 
     return new Predicate<T>(function); 
    } 

然後調用在接口上這樣的功能:

var dataGridItem = dataGrid.Items[0]; 
dataGrid1.Filter = Class_X.GetPredicate(columnRefName,textBox.Text,dataGridItem,tableRefName); 

但通用的方法是拋出異常說類型T是「對象」的類型,即使objSource是Model.TableName的類型。

我讀了一些教程,說T不能在運行時解決,那麼我應該使用「動態」而不是泛型。

我已經嘗試過使用「動態」類型,但在將Lambda表達式投射到Func < dynamic,bool>時出現異常。說我無法從< Model.TableName,bool>轉換爲< System.Object,bool>。

是否有一種更簡單的方法來過濾由反射填充的數據網格?

回答

1

在這種情況下,您不能使用泛型。 FilterFunc<object, bool>,所以:

public static Predicate<object> GetPredicate(string column, string valueP, object objSource, string table) 
{ 
    Type itemType = objSource.GetType(); 

    ParameterExpression predParam = Expression.Parameter(typeof(object), "p"); 
    Expression left = Expression.Property(Expression.Convert(predParam, itemType), "A_" + column+ "_" + table); 
    var valueStr= Expression.Constant(valueP); 
    var typeOfStr = valueStr.Type; 
    var containsMethod = typeOfStr.GetMethod("Contains", new [] { typeof(string) }); 

    var call = Expression.Call(left, containsMethod, valueStr); 

    //To handle null values. It considers null == string.Empty 
    //var left2 = Expression.Coalesce(left, Expression.Constant(string.Empty)); 
    //var call = Expression.Call(left2, containsMethod, valueStr); 

    //If you want null values to be distinct from string.Empty, it's 
    //much more complex. You'll need a temporary variable (left2) 
    //where to put the value of the property, and then you can use the 
    //Expression.Condition (that is the ? : ternary operator) to 
    //test for null values 
    //var left2 = Expression.Variable(typeof(string)); 
    //var assign = Expression.Assign(left2, left); 
    //var notNull = Expression.NotEqual(left2, Expression.Constant(null)); 
    //var call = Expression.Call(left2, containsMethod, valueStr); 
    //var condition = Expression.Condition(notNull, call, Expression.Constant(false)); 
    //var block = Expression.Block(new[] { left2 }, new Expression[] { assign, condition }); 

    Predicate<object> function = Expression.Lambda<Predicate<object>>(call, new[] { predParam }).Compile(); 
    return function; 
} 

的「絕招」是,在返回的函數的參數被澆鑄成「正確」型(objSource.GetType()獲得)

要知道,你是不是在該行的屬性測試null值(NullReferenceException如果你嘗試在null財產使用Contains

+0

這就是問題所在,對「T」型是在方法調用類型的對象,但objSource變量的類型模式.Tablename ...類型T cou ld在運行時不能解析,所以我不能創建lambda func(因爲它將使用Model.Tablename的列來對lambda執行Contains(「text」))... –

+0

@ RafaelA.M.S。更改了代碼... – xanatos

+0

@ RafaelA.M.S。重新更改了代碼...最後找到了您正在使用的「Filter」:http://msdn.microsoft.com/it-it/library/system.componentmodel.icollectionview.filter.aspx,它是一個「Predicate Filter ' – xanatos

相關問題