目录

WPF-Binding流程

一、Binding 的核心作用

Binding 的本质:把数据源对象中的某个成员绑定到 UI 控件的 DependencyPropety 上。

例:

<TextBlock Text="{Binding Name}" />

含义:

数据源对象.Name -> TextBlock.TextProperty

二、Binding 的完整工作流程

UI元素树
DataContext继承
Binding确定Source
Path定位数据
PropertyDescriptor读取属性
赋值给DependencyProperty

三、UI 元素树

WPF 中所有 UI 元素都组成树结构:

Window
 └─ Grid
     └─ StackPanel
         └─ TextBlock

这个树主要有两种:

类型 作用
Logical Tree 逻辑结构
Visual Tree 渲染结构

DataContext 继承主要发生在 Logical Tree。

四、DataContext 继承机制

DataContext 是一个可继承的 DependencyProperty。

示例:

<Window DataContext="{StaticResource person}">
    <Grid>
        <TextBlock Text="{Binding Name}"/>
    </Grid>
</Window>

继承过程:

Window.DataContext = person
Grid.DataContext = person
TextBlock.DataContext = person

所以:

{Binding Name}

实际上等价于:

Source = DataContext
Path = Name

即:

person.Name

五、Binding 如何确定 Source

Binding 的 Source 有明确的优先级:

优先级 Source类型
1 Source
2 RelativeSource
3 ElementName
4 DataContext

示例:

1.指定 Source

<TextBlock Text="{Binding Name, Source={StaticResource person}}" />

此时:

Source = person

不会再使用 DataContext。

2.使用 DataContext

<TextBlock Text="{Binding Name}" />

此时:

Source = DataContext

六、Path 的作用

Path 用于在 Source 对象中查找成员。

常见写法:

Path 含义
Name 属性
Address.City 嵌套属性
[0] 索引器
. 当前对象
/ CollectionView.CurrentItem

示例:

<TextBlock Text="{Binding Address.City}" />

解析:

Source.Address.City

七、Path 默认值

如果 Path 不写,默认值是:

Path = "."

例如:

<TextBlock Text="{Binding Source={StaticResource mystring}}" />

等价于:

<TextBlock Text="{Binding Path=., Source={StaticResource mystring}}" />

含义:

绑定数据源对象本身

八、PropertyDescriptor 读取数据

当 Binding 找到 Path 后,需要读取对象属性。

WPF 使用:

TypeDescriptor
PropertyDescriptor
GetValue()

例如:

class Person
{
    public string Name { get; set; }
}

Binding 引擎会:

Person
PropertyDescriptor(Name)
GetValue(Person)

得到:

"Tom"

九、数据变化监听

如果对象实现:

INotifyPropertyChanged

Binding 引擎会自动监听:

public event PropertyChangedEventHandler PropertyChanged;

当属性变化时:

PropertyChanged
Binding更新UI

十、赋值给 DependencyProperty

最后一步:

Binding Engine
Target DependencyProperty

例如:

<TextBlock Text="{Binding Name}" />

目标属性:

TextBlock.TextProperty

内部调用:

BindingOperations.SetBinding(
    textBlock,
    TextBlock.TextProperty,
    binding);

然后执行:

textBlock.SetValue(TextBlock.TextProperty, value)

十一、完整运行流程示例

数据对象:

class Person
{
    public string Name { get; set; } = "Tom";
}

XAML:

<Window DataContext="{StaticResource person}">
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
    </StackPanel>
</Window>

完整解析流程:

UI Tree
TextBlock
继承 DataContext
Source = Person
Path = Name
PropertyDescriptor(Name)
GetValue(Person) = "Tom"
TextBlock.TextProperty = "Tom"

最终 UI 显示:

Tom

总结

Binding 通过 UI 元素树继承 DataContext 确定 Source,再利用 Path 在 Source 对象中查找对象,并通过 PropertyDescriptor 读取值,最终赋值给目标 DependencyProperty。

UI Tree
DataContext
Source
Path
PropertyDescriptor
DependencyProperty