1.依赖属性提供的属性功能(续)
1) 元数据重写
通过定义其?PropertyMetadata,类可以定义依赖项属性的行为,例如,其默认值和属性系统回调。?很多依赖项属性类都已经将默认元数据作为其注册过程的一部分而创建。?这包含作为?WPF?API?一部分的依赖项属性。?通过其类继承继承依赖项属性的类可以重写原始的元数据,以便可以通过元数据更改的属性的特征将与任何特定于子类的要求匹配。
在依赖项属性上重写元数据的操作必须在将该属性提供给属性系统使用之前进行,也就是说,在对注册属性的对象的特定实例进行实例化之前进行。?必须在将其自身提供为OverrideMetadata?的?forType?参数的类型的静态构造内执行对?OverrideMetadata?的调用。?如果在所有者类型的实例存在之后尝试更改元数据,这将不会引发异常,但会在属性系统中导致不一致的行为。?此外,每种类型只可以重写一次元数据。?以后在同一类型上重写元数据的尝试将会引发异常。
下面示例重写MyButton的Content依赖属性,将默认值改为Override:
[csharp]?view plain?copy
-
publicclass?MyButton?:?Button??
-
{??
-
????static?MyButton()??
-
????{??
-
????????Button.ContentProperty.OverrideMetadata(typeof(MyButton),???????????newFrameworkPropertyMetadata("Override"));??
-
????}??
-
}??
通过元数据重写,在项目使用该控件时,设计时的Context就是Override了。
?
2)属性值继承
属性值继承是 Windows PresentationFoundation (WPF) 属性系统的一项功能。?属性值继承使元素树中的子元素可以从父元素那里获取特定属性的值,并继承该值,就好像它是在最近的父元素中的任意位置设置的一样。?父元素还可以通过属性值继承来获得其值,因此系统有可能一直递归到页面根元素。?属性值继承不是属性系统的默认行为;属性必须用特定的元数据设置来建立,以便使该属性能够对子元素启动属性值继承。
如果Dependency属性在用注册的时候时指定Inherits为不可继承,这样继承就会失效。
如下,将MyButton的FontSize属性置为不可继承:
[csharp]?view plain?copy
-
public?class?MyButton?:?Button??
-
{??
-
????static?MyButton()??
-
????{??
-
????????//…??
-
????????FrameworkPropertyMetadata?fm?=?newFrameworkPropertyMetadata();??
-
????????fm.Inherits?=?false;??
-
????????Button.FontSizeProperty.OverrideMetadata(typeof(MyButton),?fm);??
-
????}??
-
}??
项目中使用:
[html]?view plain?copy
-
<GridGrid.ColumnGridGrid.Column="0"?Grid.Row="1"TextElement.FontSize="20">??
-
????<Button?Width="250"Content="属性值继承"?Margin="73,28,73,169"?/>??
-
????<mycontrol:MyButtonWidthmycontrol:MyButtonWidth="250"?Margin="73,68,129"?/>??
-
</Grid>??
效果(第一个button继承了Grid的字体大小,而第二个没有继承):

2.?为依赖属性添加所有者类型
将类添加为针对不同类型注册的依赖性属性的所有者。?通过执行此操作,WPF?XAML读取器和属性系统都可以将该类识别为属性的其他所有者。?添加所有者时,也可以选择添加类来提供类型特定的元数据。使用AddOwner方法。
示例(在MyButton上添加一个标识文本(SymbolText)依赖属性,然后为其添加所有者MyLabel):
MyButton:
[csharp]?view plain?copy
-
public?class?MyButton?:?Button??
-
{??
-
????//…??
-
????public?string?SymbolText??
-
????{??
-
????????get?{?return?(string)GetValue(SymbolTextProperty);?}??
-
????????set?{?SetValue(SymbolTextProperty,?value);?}??
-
????}??
-
?? ?
-
????public?static?readonly?DependencyProperty?SymbolTextProperty?=??
-
????????DependencyProperty.Register("SymbolText",?typeof(string),?typeof(MyButton),?new?PropertyMetadata("★"));??
-
}??
MyLabel(这边支持元数据重写,修改了默认的标识文本):
[csharp]?view plain?copy
-
public?class?MyLabel?:?Label??
-
{??
-
????//…??
-
????public?static?readonly?DependencyProperty?SymbolTextProperty?=?MyButton.SymbolTextProperty.AddOwner(typeof(MyLabel),?new?PropertyMetadata("△"));??
-
????public?string?SymbolText??
-
????{??
-
????????get?{?return?(string)this.GetValue(SymbolTextProperty);?}??
-
????????set?{?this.SetValue(SymbolTextProperty,?value);?}??
-
????}??
-
}??
样式代码就不贴了。
引用代码:
[html]?view plain?copy
-
<Grid?Grid.Column="0"?Grid.Row="1"?TextElement.FontSize="20">??
-
????<Button?Width="250"?Content="属性值继承"?Margin="73,169"?/>??
-
????<mycontrol:MyButton?Width="250"?Margin="73,129"?/>??
-
????<mycontrol:MyLabel?Width="250"?Content="MyLabel"?Margin="73,118,79"/>??
-
</Grid>??
效果:

疑问:原用ImageSource做的,但是默认值一直加不上,高手请赐教,代码如下:
[csharp]?view plain?copy
-
///?<summary>??
-
///?图片??
-
///?<para>这是依赖属性</para>??
-
///?</summary>??
-
public?ImageSource?Icon??
-
{??
-
????get?{?return?(ImageSource)GetValue(IconProperty);?}??
-
????set?{?SetValue(IconProperty,?value);?}??
-
}??
-
public?static?readonly?DependencyProperty?IconProperty?=??
-
????DependencyProperty.Register("Icon",?typeof(ImageSource),?new?PropertyMetadata(new?BitmapImage(new?Uri("/MyControls;component/Image/rabbit_32.png",?UriKind.RelativeOrAbsolute))));??
3.?只读依赖属性
在 Windows Presentation Foundation(WPF) 框架中定义的某些依赖项属性为只读。?通常指定只读依赖项属性的原因是:这些属性应该用于状态确定,但是有多种因素影响该状态,从用户界面设计的角度看,仅将属性设置为该状态并不能达到预期的效果。?例如,通过鼠标输入确认,属性?IsMouseOver?实际上仅为表层状态。?任何通过避开真正的鼠标输入以编程方式设置此值的尝试都将是不可预期的并将导致产生不一致的情况。
只读依赖属性创建注意点:
-
注册属性时,调用?RegisterReadOnly?方法而不是常规的?Register?方法进行属性注册。
-
当实现 CLR"包装"属性时,请确保该包装也没有设置的实现,以使公开的公共包装的只读状态中不存在不一致现象。
-
只读注册返回的对象是?DependencyPropertyKey,而不是?DependencyProperty。?您仍应将此字段作为成员存储,但是通常不将其设置为此类型的公共成员。
示例:为MyTextBox添加只读依赖属性,内容为文本长度:
[csharp]?view plain?copy
-
public?class?MyTextBox:TextBox??
-
{?????????
-
????//只公布Get方法??
-
????///?<summary>??
-
????///?文本长度??
-
????///?</summary>??
-
????public?int?TextCount??
-
????{??
-
????????get?{?return?(int)GetValue(TextCountProperty.DependencyProperty);?}??
-
????????private?set?{?SetValue(TextCountProperty,?value);?}??
-
????}??
-
?? ?
-
????public?static?readonly?DependencyPropertyKey?TextCountProperty?=??
-
????????DependencyProperty.RegisterReadOnly("TextCount",?typeof(int),?typeof(MyTextBox),?new?PropertyMetadata(0));??
-
}??
?
4. 依赖属性元数据
依赖项属性的元数据还可以由定义依赖项属性的类来唯一地指定,可以在依赖项属性添加到另一个类时进行更改,可以由所有从定义基类继承依赖项属性的派生类来明确地重写。
依赖项属性的元数据对象可以包含以下类型的信息:
[csharp]?view plain?copy
-
public?static?DependencyProperty?Register(??
-
????string?name,--依赖项对象的名称??
-
????Type?propertyType,--属性的类型??
-
????Type?ownerType,--依赖项对象的所有者类型??
-
????PropertyMetadata?typeMetadata,--依赖项对象的属性元数据??
-
????ValidateValueCallback?validateValueCallback--对回调的引用??
-
)??
-
?? ?
-
public?PropertyMetadata(??
-
????Object?defaultValue,--依赖项对象的默认值??
-
????--每当属性的有效值更改时,属性系统都将调用该处理程序实现??
-
????PropertyChangedCallback?propertyChangedCallback,??
-
????--每当属性系统对该属性调用?CoerceValue?时都将调用此处理程序实现??
-
????CoerceValueCallback?coerceValueCallback??
-
)??
-
--核心级别具有呈现/用户界面影响的非框架属性提供属性元数据??
-
public?UIPropertyMetadata(??
-
????Object?defaultValue,??
-
????PropertyChangedCallback?propertyChangedCallback,??
-
????CoerceValueCallback?coerceValueCallback,??
-
????bool?isAnimationProhibited--是否禁止动画处理,默认为false??
-
)??
-
--框架的属性系统??
-
public?FrameworkPropertyMetadata(??
-
????Object?defaultValue,??
-
????--元数据选项标志(FrameworkPropertyMetadataOptions?值的组合)??
-
????FrameworkPropertyMetadataOptions?flags,??
-
????PropertyChangedCallback?propertyChangedCallback,??
-
????CoerceValueCallback?coerceValueCallback,??
-
????bool?isAnimationProhibited,??
-
????--此属性的绑定时使用的?UpdateSourceTrigger??
-
????UpdateSourceTrigger?defaultUpdateSourceTrigger??
-
)??
?
5.?依赖属性回调、验证及强制值
执行顺序:
验证:ValidateValueCallback
强制值:CoerceValueCallback
回调:PropertyChangedCallback
示例(仅能输入数字的TextBox,并且有最大最小值验证):
[csharp]?view plain?copy
-
///?<summary>??
-
///?文本值,仅能输入整数??
-
///?</summary>??
-
public?string?Value??
-
{??
-
????get?{?return?(string)GetValue(ValueProperty);?}??
-
????set?{?SetValue(ValueProperty,?value);?}??
-
}??
-
?? ?
-
public?static?readonly?DependencyProperty?ValueProperty?=??
-
????DependencyProperty.Register("Value",??
-
????????typeof(string),??
-
????????typeof(MyTextBox),??
-
????????new?FrameworkPropertyMetadata(??
-
????????????"5",???
-
????????????FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,??
-
????????????PropertyChanged,??
-
????????????CoerceValue,??
-
????????????true,??
-
????????????UpdateSourceTrigger.LostFocus),??
-
????????ValidateValue);??
疑问:
原继承TextBox来做的,想替换调原来的Text属性,没成功。TextBox中使用PART_ContentHost来指定输入,并且指定[ContentProperty("Text")],没找到合适的方法去替换,有高手知道的赐教下。
[csharp]?view plain?copy
-
private?static?bool?ValidateValue(object?value)??
-
{??
-
????try??
-
????{??
-
????????int?d?=?System.Convert.ToInt32(value);??
-
????????Debug.WriteLine("ValidateValue:Pass?Value:"?+?value.ToString());??
-
????????return?true;??
-
????}??
-
????catch??
-
????{??
-
????????Debug.WriteLine("ValidateValue:Fail?Value:"?+?value.ToString());??
-
????????return?false;??
-
????}??
-
}??
-
?? ?
-
private?static?object?CoerceValue(DependencyObject?d,?object?baseValue)??
-
{??
-
????try??
-
????{??
-
????????MyTextBox?box?=?(MyTextBox)d;??
-
????????int?i?=?Convert.ToInt32(baseValue);??
-
????????if?(i?>?box.MaxValue)??
-
????????{??
-
????????????i?=?box.MaxValue;??
-
????????}??
-
????????if?(i?<?box.MinValue)??
-
????????{??
-
????????????i?=?box.MinValue;??
-
????????}??
-
????????Debug.WriteLine("CoerceValue:Pass?Value:"?+?baseValue.ToString()?+?"?CoerceValue:"+i.ToString());??
-
????????((MyTextBox)d).IsLocked?=?true;??
-
????????((MyTextBox)d).Text?=?i.ToString();??
-
????????((MyTextBox)d).IsLocked?=?false;??
-
????????return?i.ToString();??
-
????}??
-
????catch??
-
????{??
-
????????Debug.WriteLine("CoerceValue:Fail?Value:"?+?baseValue.ToString());??
-
????????return?ValueProperty.DefaultMetadata.DefaultValue;??
-
????}??
-
}??
-
?? ?
-
private?static?void?PropertyChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e)??
-
{??
-
????//d.CoerceValue(MaxValueProperty);??
-
????Debug.WriteLine("PropertyChanged:Pass?Value:"?+?e.OldValue.ToString()?+?"->"?+?e.NewValue.ToString());??
-
}??
debug结果:
ValidateValue:PassValue:01
CoerceValue:PassValue:01 CoerceValue:1
ValidateValue:PassValue:1(此次调用应该由于强制回调引起)
PropertyChanged:PassValue:0->1
?
6.监听依赖属性
监听有两种方法:
a. 依赖属性回调,第5点中说明了。
b. 用DependencyPropertyDescriptor类:
使用方法如下(将Text和Value属性关联起来):
[csharp]?view plain?copy
-
public?MyTextBox()??
-
{??
-
????DependencyPropertyDescriptor?descriptor?=?DependencyPropertyDescriptor.FromProperty(MyTextBox.TextProperty,?typeof(MyTextBox));??
-
????descriptor.AddValueChanged(this,?OldTextChanged);??
-
}??
-
?? ?
-
private?void?OldTextChanged(object?sender,?EventArgs?e)??
-
{??
-
????if?(IsLocked?==?false)??
-
????{??
-
????????Value?=?Text;??
-
????}??
-
}??
?
代码
?
?
作者:FoolRabbit
出处:http://blog.csdn.net/rabbitsoft_1987欢迎任何形式的转载,未经作者同意,请保留此段声明!