如何使用WPF从bindingexpression解析绑定对象?

Phi*_*hil 21 c# data-binding wpf mvvm

嗨,有没有人知道是否有任何内置的类从bindingexpression解析绑定对象,它的DataItem和属性路径?

我正在尝试为文本框编写Blend 3行为,该行为会自动调用绑定到文本框Text属性的对象上的方法.

文本框绑定到viewmodel类的属性.我想要做的是从绑定表达式解析viewmodel类,然后对此进行调用.

我首先从行为的关联对象中检索绑定表达式,如下所示:

private BindingExpression GetTextBinding()
{
    return this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
}
Run Code Online (Sandbox Code Playgroud)

完成此操作后,如果我们查看绑定表达式,我们可以看到它通过绑定表达式的DataItem属性引用了数据上下文.

另外,我们有绑定表达式父绑定绑定的属性的相对路径.

所以,我们可以得到这些信息:

var bindingExpression = GetTextBinding();
object dataContextItem = bindingExpression.DataItem;
PropertyPath relativePropertyPath = bindingExpression.ParentBinding.Path;
Run Code Online (Sandbox Code Playgroud)

现在,这个属性路径可能是一个深度嵌套和复杂的路径,我非常希望避免(重新)实现解析.我已经搜索了.NET文档并用反射器围绕组件弹跳,但都无济于事 - 我找不到肯定必须存在的东西 - 必须有一些类来执行数据项目的路径解析(数据上下文).

有谁知道这可能存在的地方?有关解决绑定对象的替代方法的任何建议吗?

注意,我正在尝试获取绑定对象(绑定属性的父节点)(在本例中为字符串) - 我可以很容易地得到绑定值,但它是我需要的父节点.

在此先感谢您的帮助!菲尔

Kev*_*ski 26

对于将来遇到这个问题的人:

当.NET 4.5可用时,它将在BindingExpression上有许多新属性,以大大简化您的需求.

ResolvedSource - 实际绑定的对象,当您拥有像"grandparent.parent.me.Name"这样的绑定源时非​​常有用.这将返回'我'对象.

ResolvedSourcePropertyName - 绑定到的ResolvedSource上的属性的名称.在上面的例子中,"名称".

同样,将有TargetTargetName属性.

使用BindingExpression上的这些辅助属性,您可以使用更简单,更简化的反射,更有可能在极端情况下工作(索引器).


小智 24

下面是一个扩展方法的快速实现,它将完成您正在寻找的内容.我也找不到任何相关的东西.如果由于某种原因无法找到该值,则下面的方法将始终返回null.当路径包含[]时,该方法将不起作用.我希望这有帮助!

public static T GetValue<T>(this BindingExpression expression, object dataItem)            
{
    if (expression == null || dataItem == null)
    {
        return default(T);
    }

    string bindingPath = expression.ParentBinding.Path.Path;
    string[] properties = bindingPath.Split('.');

    object currentObject = dataItem;
    Type currentType = null;

    for (int i = 0; i < properties.Length; i++)
    {
        currentType = currentObject.GetType();                
        PropertyInfo property = currentType.GetProperty(properties[i]);
        if (property == null)
        {                    
            currentObject = null;
            break;
        }
        currentObject = property.GetValue(currentObject, null);
        if (currentObject == null)
        {
            break;
        }
    }

    return (T)currentObject;
}
Run Code Online (Sandbox Code Playgroud)

  • My2cents,你有没有理由传递对象dataItem?为什么不直接更改方法签名以获取一个参数而不是两个参数并从BindingExpression获取dataItem? (5认同)

Dan*_*ant 10

仅供参考,PropertyPath解析由名为PropertyPathWorker的内部MS类处理,该类位于MS.Internal.Data下的PresentationFramework中.如果你在Reflector中打开它,你会发现它非常复杂,所以我不建议尝试复制它的功能.它与整体Binding架构紧密结合.

支持所有属性路径语法的最强大的方法 - 包括附加的依赖项属性和分层遍历 - 可能是创建一个带有DependencyProperty的虚拟DependencyObject.然后,您可以从"所有者"路径创建绑定到虚拟依赖项属性,创建新的BindingExpression,然后调用表达式的UpdateTarget.从表面上看,这是一个相当重要的方法,看起来像一个简单的任务,但我认为在解析绑定属性路径的方式中有很多隐藏的问题.


jpi*_*son 8

我相信此处发布的其他StackOverflow 解决方案也可能适合您.

复制的代码块供参考,阅读原始帖子以获取Thomas Levesque提供的更多详细信息.

public static class PropertyPathHelper
{
    public static object GetValue(object obj, string propertyPath)
    {
        Binding binding = new Binding(propertyPath);
        binding.Mode = BindingMode.OneTime;
        binding.Source = obj;
        BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding);
        return _dummy.GetValue(Dummy.ValueProperty);
    }

    private static readonly Dummy _dummy = new Dummy();

    private class Dummy : DependencyObject
    {
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(Dummy), new UIPropertyMetadata(null));
    }
}
Run Code Online (Sandbox Code Playgroud)