简介
Dependency Property: 它们依赖一些其他的property和外在的影响,引起自身的变化.
如: WPF框架的编程经常和界面打交道,经常遇到的一个情况是某个属性的值的变化会影响到多个其他对象。比如当一个Button的改变大小超过了它的容器,他的容器应该自动调整大小。于是我们考虑在每个属性的set方法中触发一些事件,但很快我们发现现有的功能很难满足我们的需求,至少不能简洁漂亮的满足这些需求。
定义示例: public static readonly DependencyProperty FontSizePropery;
1.简单的element tree
通过简单的例子来理解"沿袭"(不能说是继承)
窗口构造函数将Font size 初使化为16设备无关的单位. 所有的BUTTON都会沿袭这个设置(都是WINDOW的孩子)
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Windows;
5using System.Windows.Controls;
6using System.Windows.Documents;
7
8namespace DockAndGrid
9{
10 public class SetFontSizeProperty : Window
11 {
12 [STAThread]
13 public static void Main()
14 {
15 Application app = new Application();
16 app.Run(new SetFontSizeProperty());
17 }
18
19 public SetFontSizeProperty()
20 {
21 Title = "Set size property";
22 SizeToContent = SizeToContent.WidthAndHeight;
23 ResizeMode = ResizeMode.CanMinimize;
24 FontSize = 16;
25 Double[] fntsizes = { 8,16,32};
26
27 Grid grid = new Grid();
28 Content = grid;
29
30 for (int i = 0; i < 2; i++)
31 {
32 RowDefinition row = new RowDefinition();
33 row.Height = GridLength.Auto;
34 grid.RowDefinitions.Add(row);
35 }
36 for (int i = 0; i < fntsizes.Length; i++)
37 {
38 ColumnDefinition col = new ColumnDefinition();
39 col.Width = GridLength.Auto;
40 grid.ColumnDefinitions.Add(col);
41 }
42
43 for (int i = 0; i < fntsizes.Length; i++)
44 {
45 Button btn = new Button();
46 btn.Content = new TextBlock(new Run("Set Window FontSize to " + fntsizes[i]));
47 btn.Tag = fntsizes[i];
48 btn.HorizontalAlignment = HorizontalAlignment.Center;
49 btn.VerticalAlignment = VerticalAlignment.Center;
50 btn.Click += this.WindowFontSizeOnClick;
51 grid.Children.Add(btn);
52 Grid.SetRow(btn, 0);
53 Grid.SetColumn(btn, i);
54
55 btn = new Button();
56 btn.Content = new TextBlock(new Run("Set Button FontSize to " + fntsizes[i]));
57 btn.Tag = fntsizes[i];
58 btn.HorizontalAlignment = HorizontalAlignment.Center;
59 btn.VerticalAlignment = VerticalAlignment.Center;
60 btn.Click += this.ButtonFontSizeOnClick;
61 grid.Children.Add(btn);
62 Grid.SetRow(btn, 1);
63 Grid.SetColumn(btn, i);
64 }
65 }
66
67 void WindowFontSizeOnClick(object sender, RoutedEventArgs args)
68 {
69 Button btn = args.Source as Button;
70 FontSize = (double)btn.Tag;
71 }
72
73 void ButtonFontSizeOnClick(object sender, RoutedEventArgs args)
74 {
75 Button btn = args.Source as Button;
76 btn.FontSize = (double)btn.Tag;
77 }
78
79 }
80}
81
element tree是我们能看到的(实际)能看到的视觉对像, 是对logic tree的简单处理,更容易理解程序 (font size如何被处理的), 在此程序中为window->grid->(button collection)->(textblock collection)
特点:树中较低的对像"沿袭"父亲的property,然而如果某个对像有明确的设定自己的font size,那么就不用沿袭父亲的这个property
注: Grid根本就没有fontsize property,但依然可以沿袭(内部机制,不是很明白)
property set priority: 对像自己的设定> 沿袭来的值 > 默认值
2. dependecy property 示例
在WPF中,dependency property的使用,允许以一般的方式自动进行大部分的通知.
定义: public static readonly DependencyProperty SpaceProperty;
它是public and static, 此成员只与类相关,而非与对象相关联.
注册: SpaceProperty = DependencyProperty.Register.("Name", typeof(datatype), typeof(ownertype));
实际上这个property不可以简单的这么完成,还要须要元数据等元素,并且由于是静态的成员,必须在静态构造函数中初使化
static SpaceButton()
{
//define metadata
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.DefaultValue = 1;
metadata.AffectsMeasure = true;
metadata.Inherits = true;
metadata.PropertyChangedCallback += OnSpacePropertyChanged;
//Register dependency property
SpaceProperty = DependencyProperty.Register("Space", typeof(int), typeof(SpaceButton),
metadata, ValidateSpaceValue);
}
ValidateSpaceValue: 检验值是否合法
AffectsMeasure: 影响控件的尺寸调整.
使用: .Net CLR wrapper
public int Space
{
set { SetValue(SpaceProperty, value); }
get { return (int)GetValue(SpaceProperty); }
}
注意:即使传到SetValue and GetValue方法内当参数的property的对象是静态的,而这两个方法却是实例方法, 它们的值的设定和取得都和特定的实例有关, 这个property维持目前的值,且处理所有的日常事务.
完整示例:
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using System.Windows;
6using System.Windows.Controls;
7using System.Windows.Media;
8using System.Windows.Input;
9
10namespace DependencyProperty1
11{
12 class SpaceButton : Button
13 {
14 string txt;
15 public string Text
16 {
17 get { return txt; }
18 set
19 {
20 txt = value;
21 Content = SpaceOutText(txt);
22 }
23 }
24
25 public static readonly DependencyProperty SpaceProperty;
26 public int Space
27 {
28 set { SetValue(SpaceProperty, value); }
29 get { return (int)GetValue(SpaceProperty); }
30 }
31
32 static SpaceButton()
33 {
34 //define metadata
35 FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
36 metadata.DefaultValue = 1;
37 metadata.AffectsMeasure = true;
38 metadata.Inherits = true;
39 metadata.PropertyChangedCallback += OnSpacePropertyChanged;
40
41 //Register dependency property
42 SpaceProperty = DependencyProperty.Register("Space", typeof(int), typeof(SpaceButton),
43 metadata, ValidateSpaceValue);
44 }
45
46 static bool ValidateSpaceValue(object obj)
47 {
48 int i = (int)obj;
49 return i >= 0;
50 }
51
52 //Recall method, when the property change
53 static void OnSpacePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
54 {
55 SpaceButton btn = obj as SpaceButton;
56 btn.Content = btn.SpaceOutText(btn.txt);
57 }
58
59 private string SpaceOutText(string str)
60 {
61 if (str == null)
62 return null;
63
64 StringBuilder sb = new StringBuilder();
65 foreach (char ch in str)
66 {
67 sb.Append(ch + new string(' ', Space));
68 }
69 return sb.ToString();
70 }
71 }
72
73 public class SpaceWindow : Window
74 {
75 public static readonly DependencyProperty SpaceProperty;
76 public int Space
77 {
78 set { SetValue(SpaceProperty, value); }
79 get { return (int)GetValue(SpaceProperty); }
80 }
81
82 static SpaceWindow()
83 {
84 FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
85 metadata.Inherits = true;
86
87 //Add owner to SpacePropery and override metadata
88 SpaceProperty = SpaceButton.SpaceProperty.AddOwner(typeof(SpaceWindow));
89 SpaceProperty.OverrideMetadata(typeof(SpaceWindow), metadata);
90 }
91
92 }
93
94 public class SetSpaceProperty : SpaceWindow
95 {
96 [STAThread]
97 public static void Main()
98 {
99 Application app = new Application();
100 app.Run(new SetSpaceProperty());
101 }
102
103 public SetSpaceProperty()
104 {
105 Title = "Set Space property";
106
107 SizeToContent = SizeToContent.WidthAndHeight;
108 ResizeMode = ResizeMode.CanMinimize;
109 int[] iSpace = { 0,1,2};
110
111 Grid grid = new Grid();
112 Content = grid;
113
114 for (int i = 0; i < 2; i++)
115 {
116 RowDefinition row = new RowDefinition();
117 row.Height = GridLength.Auto;
118 grid.RowDefinitions.Add(row);
119 }
120
121 for (int i = 0; i < iSpace.Length; i++)
122 {
123 ColumnDefinition col = new ColumnDefinition();
124 col.Width = GridLength.Auto;
125 grid.ColumnDefinitions.Add(col);
126 }
127
128 for (int i = 0; i < iSpace.Length; i++)
129 {
130 SpaceButton btn = new SpaceButton();
131 btn.Text = "Set window space to " + iSpace[i];
132 btn.Tag = iSpace[i];
133 btn.HorizontalAlignment = HorizontalAlignment.Center;
134 btn.VerticalAlignment = VerticalAlignment.Center;
135 btn.Click += this.WindowPropertyOnClick;
136 grid.Children.Add(btn);
137 Grid.SetRow(btn, 0);
138 Grid.SetColumn(btn, i);
139
140 btn = new SpaceButton();
141 btn.Text = "Set button spae to " + iSpace[i];
142 btn.Tag = iSpace[i];
143 btn.HorizontalAlignment = HorizontalAlignment.Center;
144 btn.VerticalAlignment = VerticalAlignment.Center;
145 btn.Click += this.ButtonPropertyOnClick;
146 grid.Children.Add(btn);
147 Grid.SetRow(btn, 1);
148 Grid.SetColumn(btn, i);
149
150 }
151 }
152
153 void WindowPropertyOnClick(object sender, RoutedEventArgs args)
154 {
155 SpaceButton btn = args.Source as SpaceButton;
156 Space = (int)btn.Tag;
157 }
158
159 void ButtonPropertyOnClick(object sender, RoutedEventArgs args)
160 {
161 SpaceButton btn = args.Source as SpaceButton;
162 btn.Space = (int)btn.Tag;
163 }
164
165
166 }
167}
168
[Question]Logical tree, Visual tree, will trace it in the next