1

WPF で DataGrid にフィルターを適用しようとしていますが、フィルター プロパティには Predicate が必要です

元:

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

しかし、私のデータグリッドはリフレクションで満たされているため、実行時にデータグリッド内のオブジェクトのタイプしか知りません。

次に、 Predicate< 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);

しかし、ジェネリック メソッドは、objSource が Model.TableName の型であっても、型 T が「オブジェクト」の型であるという例外をスローしています。

実行時に T を解決できないというチュートリアルを読んだので、ジェネリック型の代わりに「動的」を使用する必要があります。

「動的」タイプを使用してみましたが、Lambda 式を Func<dynamic, bool> にキャストしているときに例外が発生します。< Model.TableName , bool > から < System.Object , bool > に変換できないと言っています。

リフレクションで満たされたデータグリッドをフィルタリングする簡単な方法はありますか?

4

1 に答える 1

1

この場合、ジェネリックは使用できません。FilterですFunc<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うとする場合)Containsnull

于 2013-08-27T14:36:24.893 に答える