WPF入门教程系列十三——依赖属性(三)
四、 只读依赖属性
在以前在对于非WPF的功能来说,对于类的属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只读的,它们经常用于报告控件的状态和信息,像IsMouseOver等属性, 那么在这个时候对它赋值就没有意义了。 或许你也会有这样的疑问:为什么不使用一般的.Net属性提供出来呢?一般的属性也可以绑定到元素上呀?这个是由于有些地方必须要用到只读依赖属性,比如 Trigger等,同时也因为内部可能有多个提供者修改其值,所以用.Net属性就不能完成天之大任了。
那么一个只读依赖属性怎么创建呢?其实创建一个只读的依赖属性和创建一个一般的依赖属性大同小异。不同的地方就是DependencyProperty.Register变成了DependencyProperty.RegisterReadOnly。和前面的普通依赖属性一样,它将返回一个 DependencyPropertyKey。而且只提供一个GetValue给外部,这样便可以像一般属性一样使用了,只是不能在外部设置它的值罢了。
下面我们就用一个简单的例子来概括一下:
public partial class WindowReadOnly : Window
{
public WindowReadOnly ()
{
InitializeComponent(); //用SetValue的方法来设置值
DispatcherTimer timer =
new DispatcherTimer(TimeSpan.FromSeconds(),
DispatcherPriority.Normal,
(object sender, EventArgs e)=>
{
int newValue = Counter == int.MaxValue ? : Counter + ;
SetValue(counterKey, newValue);
},
Dispatcher); } //属性包装器,只提供GetValue
public int Counter
{
get { return (int)GetValue(counterKey.DependencyProperty); }
} //用RegisterReadOnly来代替Register来注册一个只读的依赖属性
private static readonly DependencyPropertyKey counterKey =
DependencyProperty.RegisterReadOnly("Counter",
typeof(int),
typeof(WindowReadOnly),
new PropertyMetadata());
}
XAML代码:
<Window x:Name="winReadOnly" x:Class="WpfApp1.WindowReadOnly"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowDepend" Height="300" Width="300">
<Grid>
<Viewbox>
<TextBlock Text="{Binding ElementName=winReadOnly, Path=Counter}" />
</Viewbox>
</Grid>
</Window>
效果如下图所示:
五、 附加属性
现在我们再继续探讨另外一种特殊的依赖属性——附加属性。附加属性是一种特殊的依赖属性。这是WPF的特性之一,通俗的理解起来就是,别人有的属性,由于你跟他产生了关系所以你也有了这个属于他的属性。
附加属性是说一个属性本来不属于某个对象,但由于某种需求而被后来附加上,也就是把对象放入一个特定环境后对象才具有的属性就称为附加属性,附加属性的作
用就是将属性与数据类型解耦,让数据类型的设计更加灵活,举例,一个TextBox被放在不同的布局容器中时就会有不同的布局属性,这些属性就是由布局容
器为TextBox附加上的,附加属性的本质就是依赖属性,二者仅仅在注册和包装器上有一点区别。
附加属性是依赖属性的一种特殊形式,它可以让用户在一个元素中设置其他元素的属性。一般来说,附加属性是用于一个父元素定位其他元素布局 的。就像Grid和DockPanel元素就包含附加属性。Grid使用附加属性来指定包含子元素的特定行和列,而DockPanel使用附加属性是来指
定子元素应该停靠在面板中的何处位置。
附加属性就是自己没有这个属性,在某些上下文中需要就被附加上去。比如StackPanel的Grid.Row属性,如果我们定义StackPanel类时定义一个Row属性是没有意义的,因为我们并不知道一定会放在Grid里,这样就造成了浪费。
例如,下面转场控件的定义使用了Grid的Row属性来将自身定位到特定的行中。
<Grid> <Grid.RowDefinitions> <RowDefinition Height="101*"/> <RowDefinition Height="80"/> <RowDefinition Height="80"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" >
尽管对于一个普通的WPF开发人员来说,理解依赖和附加属性并不一定是必须的,但是掌握好WPF系统的整个运行机制对于提升WPF应用技术是非常重要的。
使用附加属性,可以避开可能会防止一个关系中的不同对象在运行时相互传递信息的编码约定。一定可以针对常见的基类设置属性,以便每个对象只需获取和
设置该属性即可。但是,你可能希望在很多情况下这样做,这会使你的基类最终充斥着大量可共享的属性。它甚至可能会引入以下情况:在数百个后代中,只有两个 后代尝试使用一个属性。这样的类设计很糟糕。为了解决此问题,我们使用附加属性概念来允许对象为不是由它自己的类结构定义的属性赋值。在创建对象树中的各
个相关对象之后,在运行时从子对象读取此值。
最好的例子就是布局面板。每一个布局面板都需要自己特有的方式来组织它的子元素。如Canvas需要Top和left来布
局,DockPanel需要Dock来布局。当然你也可以写自己的布局面板(在上一篇文章中我们对布局进行了比较细致的探讨,如果有不清楚的朋友也可以再
回顾一下)。
下面代码中的Button 就是用了Canvas的Canvas.Top和Canvas.Left="20" 来进行布局定位,那么这两个就是传说中的附加属性。
<Canvas>
<Button Canvas.Top="20" Canvas.Left="20" Content="Knights Warrior!"/>
</Canvas>
定义附加属性的方法与定义依赖属性的方法一致,前面我们是使用DependencyProperty.Register来注册一个依赖属性,只是在注册属性时使用的是RegisterAttach()方法。这个RegisterAttached的参数和 Register是完全一致的,那么Attached(附加)这个概念又从何而来呢?
其实我们使用依赖属性,一直在Attached(附加)。我们注册(构造)一个依赖属性,然后在DependencyObject中通过 GetValue和SetValue来操作这个依赖属性,也就是把这个依赖属性通过这样的方法关联到了这个DependencyObject上,只不过是 通过封装CLR属性来达到的。那么RegisterAttached又是怎样的呢?
下面我们来看一个最简单的应用:首先我们注册(构造)一个附加属性
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; namespace WpfApp1.Services { public class TurnoverManager : DependencyObject { //通过静态方法的形式暴露读的操作 public static double GetAngle(DependencyObject obj) { return (double)obj.GetValue(AngleProperty); } //通过静态方法的形式暴露写的操作 public static void SetAngle(DependencyObject obj, double value) { obj.SetValue(AngleProperty, value); } //通过使用RegisterAttached来注册一个附加属性 public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(TurnoverManager), new PropertyMetadata(0.0, OnAngleChanged)); //根据附加属性中的值,当值改变的时候,旋转相应的角度。 private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var element = obj as UIElement; if (element != null) { element.RenderTransformOrigin = new Point(0.5, 0.5); element.RenderTransform = new RotateTransform((double)e.NewValue); } } } }
然后,我们在程序中使用这个我们自己定义的附加属性
<Window x:Class="WpfApp1.WindowTurnover" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp1.Services" Title="WindowTurnover" Height="400" Width="500" Loaded="Window_Loaded"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="313*"/> <RowDefinition Height="57*"/> </Grid.RowDefinitions> <Canvas Grid.Row="0"> <Ellipse Name="ellipseRed" Fill="Red" Width="100" Height="60" Canvas.Left="56" Canvas.Top="98" local:TurnoverManager.Angle="{Binding ElementName=sliderAngle, Path=Value}"/> <Rectangle Name="ellipseBlue" Fill="Blue" Width="80" Height="80" Canvas.Left="285" Canvas.Top="171" local:TurnoverManager.Angle="45" /> <Button Name="btnWelcome" Content="欢迎光临" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:TurnoverManager.Angle="60"/> </Canvas> <WrapPanel Grid.Row="1"> <Label Content="角度大小" /> <Slider x:Name="sliderAngle" Minimum="0" Maximum="240" Width="300" />
</WrapPanel> </Grid> </Window>
在XAML中就可以使用刚才注册(构造)的附加属性了:如下图。
通过调整角度值,显示不同的效果如下两图。图1,图2。
图1
图2
WPF入门教程系列十三——依赖属性(三)的更多相关文章
- WPF入门教程系列十一——依赖属性(一)
一.依赖属性基本介绍 本篇开始学习WPF的另一个重要内容依赖属性. 大家都知道WPF带来了很多新的特性,其中一个就是引入了一种新的属性机制——依赖属性.依赖属性出现的目的是用来实现WPF中的样式.自动 ...
- WPF入门教程系列二十三——DataGrid示例(三)
DataGrid的选择模式 默认情况下,DataGrid 的选择模式为“全行选择”,并且可以同时选择多行(如下图所示),我们可以通过SelectionMode 和SelectionUnit 属性来修改 ...
- WPF入门教程系列三——Application介绍(续)
接上文WPF入门教程系列二——Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...
- WPF入门教程系列二——Application介绍
一.Application介绍 WPF和WinForm 很相似, WPF与WinForm一样有一个 Application对象来进行一些全局的行为和操作,并且每个 Domain (应用程序域)中仅且只 ...
- WPF入门教程系列(二) 深入剖析WPF Binding的使用方法
WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...
- WPF入门教程系列(一) 创建你的第一个WPF项目
WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...
- WPF入门教程系列一
WPF入门教程 一. 前言 公司项目基于WPF开发,最近项目上线有点空闲时间写一篇基于wpf的基础教材,WPF也是近期才接触,学习WPF也是在网上查资料与微软的MSDN进行学习,写本博客的目为了温 ...
- WPF入门教程系列十四——依赖属性(四)
六.依赖属性回调.验证及强制值 我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤: 借用一个常见的图例,介绍一下WPF属性系统对依赖属性操作的基本步骤: 第一步,确定Base ...
- WPF入门教程系列十二——依赖属性(二)
二. 依赖属性的优先级 由于WPF 允许我们可以在多个地方设置依赖属性的值,所以我们就必须要用一个标准来保证值的优先级别.比如下面的例子中,我们在三个地方设置了按钮的背景颜色,那么哪一个设置才会是最终 ...
随机推荐
- bootstrap框架 导航条组件使用
本文记载boot 导航条组件使用方法 导航条组件 导航条是在您的应用或网站中作为导航页头的响应式基础组件.它们在移动设备上可以折叠(并且可开可关),且在视口(viewport)宽度增加时逐渐变为水平展 ...
- 算法入门笔记------------Day4
1.WERTYU 输入一个错位后敲出的字符串,输出打字员本来想打出的字 #include<stdio.h> char *s="`1234567890-=QWERTYUIOP[]\ ...
- Windows Phone 8.1 新特性 - 页面导航
本篇介绍一下Windows Phone 8.1 中页面导航的实现方式. 大家对Windows Phone 8 中页面导航的实现一定不陌生,我们使用 NavigationService 来实现.具体写法 ...
- src与 href 的一些区别
src用于替换当前元素,href用于在当前文档和引用资源之间确立联系. src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置:在请求 src 资源时会将其指 ...
- 攒机I7
CPU : I7 4790K +Z97 = 3200 散热器 :九州风神玄冰400 = 99 硬盘 :希捷 1TB 64M = 310 机箱: 金河田超越白 = 200 内存 DDR3金士顿8G = ...
- hdu 5104 素数打表水题
http://acm.hdu.edu.cn/showproblem.php?pid=5104 找元组数量,满足p1<=p2<=p3且p1+p2+p3=n且都是素数 不用素数打表都能过,数据 ...
- Link To Sql简单
Linq及其扩展 Linq是一种数据查询语言(它能够从多种数据源中查询数据). 现在基于Linq的扩展有: Linq To Object:主要是从内存对象中查询数据 Linq To Sql:主要是从M ...
- I/O优化篇
转载:http://blog.csdn.net/gzh0222/article/details/9227393 很不错 1.系统学习 IO性能对于一个系统的影响是至关重要的.一个系统经过多项优化以后, ...
- asp.net中实现文件下载功能
//TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { /* ...
- python 之readability与BeautifulSoup
以前要采集某个网页,一般做法是写程序源代码爬出来,然后用正则去匹配出来,这种针对指定的网页去爬效果还可以,但是如果是批量的网页这种实现就会变得不现实,在这时候就有readability出手的意义了,r ...