【问题标题】:How to resolve a binding expression set on a custom Dependancy Property?如何解析自定义依赖属性上的绑定表达式集?
【发布时间】:2015-04-05 07:12:38
【问题描述】:

我制作了一个自定义的可搜索组合框,在默认的 CollectionView 上定义了一个过滤器

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 信息

【问题讨论】:

  • 我不确定我是否完全理解这个问题,但您可以使用反射从字符串中动态获取属性值。 value.GetType().GetProperty(FilterPropertyPath).GetValue(value) 请注意,如果未找到具有给定名称的属性,则 GetProperty 将返回 null。
  • @SzabolcsDézsi,关于这种方法的两个问题,1. 反射非常慢,2. 我需要它来处理嵌套路径?比如 A 类 { B 类 { C 类 { string GetMe { get;放; } } } },然后是 value.GetType().GetProperty("A.B.C.GetMe").GetValue(value)
  • 您说得对。没有考虑嵌套路径。

标签: c# wpf xaml


【解决方案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");

“结果”字符串将设置为“StackOverflow”。因此,您的过滤谓词将变为:

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

希望对你有帮助。

【讨论】:

  • 使用 lambda 表达式代替反射似乎是一个非常聪明的举动(将尝试基准和更新速度比较)
  • @II Vic,代码非常好,不需要运行任何综合基准测试,有一个虚拟应用程序,通过创建一个新的虚拟绑定来解决特定用户控件的绑定表达式;用您的表达式树方法替换该代码可以显着提高性能(尝试了多次,唯一的变化就是这种方法)。
猜你喜欢
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-07
  • 1970-01-01
  • 1970-01-01
  • 2010-11-25
相关资源
最近更新 更多