如何解析自定义依赖项属性上的绑定表达式?

时间:2015-04-05 07:12:39

标签: c# wpf xaml

我制作了一个自定义的Searchable ComboBox,在默认的CollectionView上定义了一个Filter

CollectionViewSource.GetDefaultView(this.ItemsSource)
view.Filter += FilterPredicate;

ComboBox的过滤谓词:

private bool FilterPredicate(object value)
{
    return PropertyPathHelper.GetValue(value, FilterPropertyPath).ToString().Contains(PART_FilterTextBox.Text);
}
//value is instance of current filtered item: Student{ FullName="SunnyXyz" , Age=30 }
//& FilterPropertyPath="FullName"

FilterPropertyPath 是一个“字符串”DependancyProperty,其作用类似于DisplayMemberPath,用于定位要在绑定项目中应用过滤的文本属性。 PropertyPathHelper.GetValue创建一个虚拟绑定&解析绑定路径,但这种方法很慢/不优雅/似乎不是正确的方法。 (来自https://stackoverflow.com/a/7041604/852318

任何人都可以使用其他正确方式或更优雅的方式来传递FilterPropertyPath信息

1 个答案:

答案 0 :(得分:1)

您可以使用Expression Trees来实现目标。

您可以使用辅助类来构建,然后执行一个表达式,该表达式为您提供PropertyPath的值。代码如下:

public static class PropertyPathHelper
{
    public static T GetValue<T>(object instance, string propPath)
    {
        Delegate runtimeDelegate;

        System.Linq.Expressions.ParameterExpression instanceParameter =
            System.Linq.Expressions.Expression.Parameter(instance.GetType(), "p");

        string[] properties = propPath.Split('.');

        System.Linq.Expressions.MemberExpression currentExpression =
            System.Linq.Expressions.Expression.PropertyOrField(instanceParameter, properties[0]);

        System.Linq.Expressions.LambdaExpression lambdaExpression =
            System.Linq.Expressions.Expression.Lambda(currentExpression, instanceParameter);

        for (int i = 1; i < properties.Length; i++)
        {
            currentExpression = System.Linq.Expressions.Expression.PropertyOrField(lambdaExpression.Body, properties[i]);
            lambdaExpression = System.Linq.Expressions.Expression.Lambda(currentExpression, instanceParameter);
        }

        runtimeDelegate = lambdaExpression.Compile();

        return (T)runtimeDelegate.DynamicInvoke(instance);
    }
}

当然,您可以通过使用存储已编译的lambda表达式的静态字典来改进该方法。与使用反射相比,表达式更快。 您可以这样使用此方法:

One one = new One() { Two = new Two() { Three = new Three() { Description = "StackOverflow" } } };
string result = PropertyPathHelper.GetValue<string>(one, "Two.Three.Description");

&#34;结果&#34; string将被设置为&#34; StackOverflow&#34;。因此,您的过滤谓词将变为:

private bool FilterPredicate(object value)
{
    return PropertyPathHelper.GetValue<string>(value, FilterPropertyPath).Contains(PART_FilterTextBox.Text);
}

我希望它可以帮到你。