WPF:依赖项属性与常规CLR属性的区别是什么?
在WPF中,“依赖属性”到底意味着什么 我读过微软的,但它并没有真正让我着迷。那篇文章的部分内容是: 样式和模板是使用依赖属性的两个主要激励场景。样式对于设置定义应用程序用户界面(UI)的属性特别有用。样式通常在XAML中定义为资源。样式与属性系统交互,因为它们通常包含特定属性的“setter”,以及基于另一个属性的实时值更改属性值的“触发器” 然后示例代码如下所示:WPF:依赖项属性与常规CLR属性的区别是什么?,wpf,dependency-properties,Wpf,Dependency Properties,在WPF中,“依赖属性”到底意味着什么 我读过微软的,但它并没有真正让我着迷。那篇文章的部分内容是: 样式和模板是使用依赖属性的两个主要激励场景。样式对于设置定义应用程序用户界面(UI)的属性特别有用。样式通常在XAML中定义为资源。样式与属性系统交互,因为它们通常包含特定属性的“setter”,以及基于另一个属性的实时值更改属性值的“触发器” 然后示例代码如下所示: <Style x:Key="GreenButtonStyle"> <Setter Property="Co
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
....
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>
....
我是绿色的!
但我不明白这有什么特别之处。这是否意味着,当我将按钮上的Style
设置为给定样式时,实际上是在隐式设置Background
?这是问题的关键吗
在WPF中,“依赖属性”到底意味着什么
为了成为依赖属性,该属性实际上必须静态地定义为类上的。依赖项属性系统与标准CLR属性非常不同
但是,依赖项属性的处理方式非常不同。类型以静态方式定义依赖项属性,并提供默认值。在需要实例之前,运行时实际上不会为实例生成值。这提供了一个好处——属性只有在请求类型时才存在,因此您可以拥有大量属性而不会产生开销
这就是使样式化属性起作用的原因,但对于允许附加属性、通过可视树的属性“继承”以及WPF依赖的许多其他内容也很重要
例如,以
DataContext
依赖项属性为例。通常,为窗口或用户控件设置DataContext
依赖项属性。默认情况下,该窗口中的所有控件自动“继承”其父控件的DataContext
proeprty,这允许您为控件指定数据绑定。使用标准CLR属性,您需要为窗口中的每个控件定义DataContext,以使绑定正常工作。以下是我一直希望有人为我编写的关于依赖项属性如何工作的解释。这是不完整的,而且很可能是错误的,但它将帮助您对它们有足够的理解,从而能够掌握您所阅读的文档
依赖属性是通过DependencyObject
类的方法获取和设置的类似属性的值。它们可以(而且通常确实)看起来非常像CLR属性,但它们不是。这是关于他们的第一件令人困惑的事情。依赖属性实际上是由几个组件组成的
下面是一个例子:
Document
是RichTextBox
对象的属性。这是一个真正的CLR属性。也就是说,它有一个名称、一个类型、一个getter和一个setter,就像任何其他CLR属性一样。但是与“普通”属性不同,RichTextBox
属性不仅仅在实例中获取和设置私有值。在内部,它是这样实现的:
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
public static DependencyProperty DocumentProperty = DependencyProperty.Register(
"Document",
typeof(FlowDocument),
typeof(RichTextBox));
设置Document
时,传入的值将与DocumentProperty
一起传递到SetValue
。那是什么?那么GetValue
是如何得到它的值的呢?还有…为什么
首先是什么。RichTextBox
上定义了一个名为DocumentProperty
的静态属性。声明此属性时,其操作如下:
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
public static DependencyProperty DocumentProperty = DependencyProperty.Register(
"Document",
typeof(FlowDocument),
typeof(RichTextBox));
在本例中,Register
方法告诉依赖属性系统,RichTextBox
——类型,而不是实例——现在有一个名为Document
的类型为FlowDocument
的依赖属性。此方法将此信息存储在某处。其中,确切地说,是一个对我们隐藏的实现细节
当文档
属性的setter调用设置值
时,设置值
方法查看文档属性
参数,验证它确实是属于RichTextBox
的属性,并且值
是正确的类型,然后将其新值存储在某处。DependencyObject
的文档对这个实现细节并不熟悉,因为您实际上不需要了解它。在我关于这些东西如何工作的心智模型中,我假设有一个Dictionary
类型的属性是DependencyObject
的私有属性,因此派生类(如RichTextBox
)看不到它,但GetValue
和SetValue
可以更新它。但谁知道呢,也许是修道士写在羊皮纸上的
无论如何,这个值现在被称为“本地值”,也就是说它是这个特定RichTextBox
的本地值,就像普通属性一样
所有这些的要点是:
GetValue
和SetValue
来获取和设置它,但是除非您正在对依赖属性系统进行操作,否则您可能不需要这样做 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SampleWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static readonly DependencyProperty Count1Property;
private int _Count2 = 2;
public int Count2
{
get { return _Count2; }
set { _Count2 = value; }
}
public MainWindow()
{
return;
}
static MainWindow()
{
// Register the property
MainWindow.Count1Property =
DependencyProperty.Register("Count1",
typeof(int), typeof(MainWindow),
new FrameworkPropertyMetadata(1,
new PropertyChangedCallback(OnCount1Changed)));
}
// A .NET property wrapper (optional)
public int Count1
{
get { return (int)GetValue(MainWindow.Count1Property); }
set { SetValue(MainWindow.Count1Property, value); }
}
// A property changed callback (optional)
private static void OnCount1Changed(
DependencyObject o, DependencyPropertyChangedEventArgs e) {
}
private void btnButton1_Click_1(object sender, RoutedEventArgs e)
{
Count1++;
}
private void btnButton1_Click_2(object sender, RoutedEventArgs e)
{
Count2++;
}
}
}
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="About WPF Unleashed" SizeToContent="WidthAndHeight"
FontSize="30" FontStyle="Italic"
Background="OrangeRed">
<StackPanel>
<Label FontWeight="Bold" FontSize="20" Foreground="White">
WPF Unleashed (Version 3.0)
</Label>
<Label>© 2006 SAMS Publishing</Label>
<Label>Installed Chapters:</Label>
<ListBox>
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button MinWidth="75" Margin="10">Help</Button>
<Button MinWidth="75" Margin="10">OK</Button>
</StackPanel>
<StatusBar>You have successfully registered this product.</StatusBar>
</StackPanel>
</Window>