ElementName与RelativeSource局限性

引言

xaml代码中属性的绑定主要是通过元素名或类型进行查找绑定和解析的,但是当在后台生成控件或面对popup、menuitem时,发现他们都查找不到这时为什么呢?

局限性

1、无法绑定后台生成控件

xaml中声明的元素会自动被添加进可视化树中,但后台通过代码添加的控件无法被xaml代码绑定,如下:

//后台
TextBox tb = new TextBox("tb");

//xaml

这样是绑定不成功的,我们需要注册 tb 这个名称,可以临时解决这个问题,但RelativeSource绑定时仍然找不到

//后台
TextBox tb = new TextBox("tb");
this.RegisterName(tb.Name,tb);

//xaml

 对于RelativeSource可以通过x:Reference 解决,

 但仍然有问题,如果我们用x:Reference 将 控件的Tag绑定到自身 会出现循环依赖错误。因为Tag依赖 Button,而Button此时还没有构建完成。

2、控件Tag、DataGridTextColumn元素无法绑定

因为Tag不存在于可视化树中,所以也无法绑定。用x:Reference 可以解决绑定非自身属性,但通常我们都要绑定父类的DataContext.

3、ContextMenu、Tooltip

都在Popup可视化树上,也无法绑定父类控件属性。但他们有个PlacementTarget代表父类对象, 后台可以通过 ContextMenuService.GetPlacementTarget(dp) 获取dp的父控件,前端则没有办法。

注意:他们是可以继承DataContext,可以绑定ViewModel的属性。

万能解决方案

BindingProxy

很简单的一个类,主要是继承了 Freezable。

public class BindingProxy : Freezable
{
 
    protected override Freezable CreateInstanceCore()=> new BindingProxy();

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

可以添加到资源里面使用:


    

 也可以直接添加到Button资源里使用:

只要父子关系成立,就可以绑定,写在何处都无所谓。

同样也有一个继承了Freezable类的现有元素:DiscreteObjectKeyFrame,它通常用在动画上面,没有BindingProxy轻量。

你可能感兴趣的:(wpf)