为何ElementName绑定找不到ucSearchView,RelativeSource却可正常工作?
绑定测试结果
测试1:查找当前SearchComboBox
- 绑定表达式:
{Binding Ugabuga, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}System.Windows.Data Error: 40 : BindingExpression path error: 'Ugabuga' property not found on 'object' ''SearchComboBox' (Name='ucSearchComboBox')'.
- 绑定表达式:
{Binding Ugabuga, ElementName=ucSearchComboBox}System.Windows.Data Error: 40 : BindingExpression path error: 'Ugabuga' property not found on 'object' ''SearchComboBox' (Name='ucSearchComboBox')'.
结论:两种方式均成功找到ucSearchComboBox对象
测试2:查找上层SearchView
- 绑定表达式:
{Binding Ugabuga, RelativeSource={RelativeSource AncestorType={x:Type UserControl}, AncestorLevel=2}}System.Windows.Data Error: 40 : BindingExpression path error: 'Ugabuga' property not found on 'object' ''SearchView' (Name='ucSearchView')'.
- 绑定表达式:
{Binding Ugabuga, ElementName=ucSearchView}System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=ucSearchView'.
核心疑问:为何RelativeSource能找到ucSearchView,ElementName却不行?是否和名称作用域有关?
原因解析
确实和**名称作用域(Name Scopes)**直接相关,具体逻辑如下:
- DataTemplate的独立名称作用域
DataTemplate会创建完全独立的名称作用域,与定义它的父控件(SearchComboBox)的名称作用域相互隔离。也就是说:
- DataTemplate内部的元素无法通过
ElementName引用到模板外部、不属于当前名称作用域的元素 ucSearchView属于SearchView的名称作用域,不在DataTemplate的名称作用域内,因此ElementName=ucSearchView无法找到目标
- RelativeSource的视觉树查找逻辑
RelativeSource是通过遍历**视觉树(Visual Tree)**的层级关系定位目标元素,完全不依赖名称作用域:
- 绑定引擎会沿着视觉树向上遍历,按照
AncestorType和AncestorLevel的条件匹配祖先元素 - 只要目标元素在视觉树的祖先链中,就能被找到,不管它属于哪个名称作用域
- 关于
ElementName=ucSearchComboBox能成功的补充ucSearchComboBox是承载该DataTemplate的控件,WPF对这种场景有特殊处理:绑定引擎会通过模板的关联上下文,间接访问到承载模板的控件的名称作用域,因此可以找到ucSearchComboBox;但这种特殊处理只延伸到承载模板的直接父控件,无法覆盖更上层的ucSearchView。
内容的提问来源于stack exchange,提问作者Krystian Sikora

