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"九、数据变化监听
如果对象实现:
INotifyPropertyChangedBinding 引擎会自动监听:
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