依赖属性位于 DependencyObject 上,所有 WPF UI 元素都从该 DependencyObject 派生(并且仅在其中工作),因为它是静态的,并将其值保存在分配给特定 DependencyObject 的一种集合中(在该集合上定义了依赖属性)。可以在实际 DependencyObject 之外的类中定义依赖属性,以扩展其功能,而无需修改原始用户控件类。
当您编写用户控件并希望 ViewModel 允许绑定值并在其更改时接收通知时,您需要创建一个依赖属性。
将它想象成一根 USB 电缆,其中有一个公插头和一个母插座。 CLR 属性就像插头,依赖属性就像插座。
依赖属性允许您存储与控件关联但不属于实例的内容。正如您在MSDN Examples 上看到的那样
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
...
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
依赖属性是静态的,GetValue 和 SetValue 是 DependencyObject(所有 WPF UI 元素都基于的基类)的方法。
依赖属性(和附加属性/附加行为)也可用于扩展UserControl 的功能,而无需从实际的用户控件类型继承,即当某个值发生更改时通知 ViewModel原始用户控制。
- 依赖属性是否与 CLR 属性相同,CLR 属性在更改时会发出 PropertyChanged 事件?
不,不一样。它们都是数据绑定引擎的两个方面。在视图上定义了一个 DP,以允许视图模型绑定一个 INPC 属性(上升的属性PropertyChanged 事件)
- Dependency 属性是写在视图本身中(MyPage.xaml.cs)还是可以包含在视图模型中(MyPageViewModel.cs)?
DP 是 View-Layer 的一部分,因为它们依赖于 DependencyObject,这是 WPF 框架的一部分,因此是视图关注点。虽然从技术上讲,没有什么可以阻止您在 ViewModel 中使用它们,但这会导致您的 ViewModel 与某种 View 技术紧密耦合,因此它不完全符合 MVVM 模式。
请注意,尽管对依赖属性进行单元测试可能非常困难,因为它们不将值存储在定义它们的类上,而是存储在某种字典中,其中 GetValue/@ 987654333@ 方法扭曲。
最后但同样重要的是,因为DependencyObject 是所有 UI 的基类,它也是从它派生的大多数类线程仿射,这意味着您只能从您创建的线程访问它,这可能会导致您在单元测试(特别是如果测试像 MSTest 过去那样并行运行。不知道到今天仍然如此)和代码中都非常痛苦。
- 在 MVVM 模式中,我们更多地使用 CLR 属性,它在属性更改期间发出事件。那么依赖属性可以用这种CLR属性代替吗?
在 ViewModels 中你可以而且你应该使用INotifyPropertyChanged。如果您正在开发用户控件,则不应将 DP 替换为“CLR”属性,因为这会使该属性无法与 XAML 中的数据绑定一起使用。
如果您的 UI 元素应该公开一个可与数据绑定一起使用的属性,您必须使用依赖属性(或非常相似的附加属性,但您将附加属性放在子元素上。Grid.Row 和 @987654337 @ 是附加属性的示例)。