依赖属性(Dependency Properties)
1.依赖属性提供的属性功能(续)
下面示例重写MyButton的Content依赖属性,将默认值改为Override:
- 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,73,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,28,73,169" />
- <mycontrol:MyButton Width="250" Margin="73,68,73,129" />
- <mycontrol:MyLabel Width="250" Content="MyLabel" Margin="73,118,73,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), typeof(MyButton), new PropertyMetadata(new BitmapImage(new Uri("/MyControls;component/Image/rabbit_32.png", UriKind.RelativeOrAbsolute))));
示例:为MyTextBox添加只读依赖属性,内容为文本长度:
- 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));
- }
依赖项属性的元数据还可以由定义依赖项属性的类来唯一地指定,可以在依赖项属性添加到另一个类时进行更改,可以由所有从定义基类继承依赖项属性的派生类来明确地重写。
- 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
- )
示例(仅能输入数字的TextBox,并且有最大最小值验证):
- /// <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
监听有两种方法:
a. 依赖属性回调,第5点中说明了。
b. 用DependencyPropertyDescriptor类:
使用方法如下(将Text和Value属性关联起来):
- 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
欢迎任何形式的转载,未经作者同意,请保留此段声明!