WPF入门教程(七)---依赖属性(3)

2018年08月24日 08:33:43 weixin_38029882 阅读数:50

四、 只读依赖属性

  在以前在对于非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(1), DispatcherPriority.Normal, (object sender, EventArgs e)=> { int newValue = Counter == int.MaxValue ? 0 : Counter + 1; 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(0)); }

XMAL代码

<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); } } } }

然后,我们在程序中使用这个我们自己定义的附加属性

    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>

在XAML中就可以使用刚才注册(构造)的附加属性了:如下图。 
 
效果如图所示 

转载于:https://www.cnblogs.com/LiZhongZhongY/p/10870137.html

WPF入门教程(七)---依赖属性(3)(转)相关推荐

  1. 前端入门教程(七)CSS属性设置

    宽和高 width属性可以为元素设置宽度. height属性可以为元素设置高度. 块级标签才能设置宽度,内联标签的宽度由内容来决定. 字体属性 文字字体 font-family可以把多个字体名称作为一 ...

  2. WPF入门教程(八)--依赖属性(4)(转)

    WPF入门教程(八)--依赖属性(4) 2018年08月27日 11:35:55 weixin_38029882 阅读数:71 我们通过下面的这幅图,简单介绍一下WPF属性系统对依赖属性操作的基本步骤 ...

  3. WPF入门教程系列十三——依赖属性(三)

    四. 只读依赖属性 在以前在对于非WPF的功能来说,对于类的属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只 ...

  4. WPF入门教程系列四——Dispatcher介绍

    WPF入门教程系列四--Dispatcher介绍 一.Dispatcher介绍 微软在WPF引入了Dispatcher,那么这个Dispatcher的主要作用是什么呢? 不管是WinForm应用程序还 ...

  5. WPF入门教程系列三——Application介绍(续)

    接上文WPF入门教程系列二--Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...

  6. WPF 入门教程(一)

    WPF 入门教程(一) 1.布局规则 1.WPF 窗体中,一个窗体只能持有一个空间,当需要展示多个控件时,则需要首先设置一个容器控件(Container).控件的布局有容器来决定. 2.控件应避免明确 ...

  7. WPF入门教程-转载

    最近为了做炫酷的UI,了解了WPF,之前一直是使用winform的,界面也是古老的不行. 在园里找到了一个大佬以前写的教程,备注一下.按照系列教程走下来,可以直接上手了. 备忘传送门>>& ...

  8. WPF xaml中列表依赖属性的定义

    原文:WPF xaml中列表依赖属性的定义 列表内容属性 如上图,是一个列表标题排序控件,我们需要定义一个标题列表,从而让调用方可以自由的设置标题信息. 在自定义控件时,会遇到列表依赖属性,那么该如何 ...

  9. WPF学习笔记一 依赖属性及其数据绑定

    本文想通过由浅入深的讲解让读者比较深的理解依赖属性.  首先,我们回顾一下依赖属性的发展历史. 最初,人们提出面向对象编程时,并没有属性这个说法,当时叫做成员变量.一个对象由成员变量和成员函数组成,如 ...

最新文章

  1. 新书推荐 |《PostgreSQL实战》出版
  2. CocoStudio 1.3和1.4.1导入Flash文件注意事项(转载并有修改)
  3. [iPhone-Sqlite3]sqlite3_prepare_v2() 不返回 SQLITE_OK,调试
  4. Mouse Without Borders 一套鼠标键盘控制多台电脑
  5. bat 发送post请求_get post 请求
  6. 荣耀X20 SE评测:6400万高清美拍 2000元以下真香现场
  7. 构架https服务器
  8. tensorflow实现余弦cosine相似度
  9. iOS中的 深拷贝和浅拷贝
  10. 共享单车的定位,应该是利用手机实现
  11. Linux 完全卸载 MySQL
  12. linux下检查磁盘是否有坏道,badblocks 检查硬盘是否有坏道
  13. 用R语言看武汉市武昌区房租出租情况
  14. 计算机应用中双绞线细铜线几根,《计算机应用基础_在线作业_E100.doc
  15. 视频播放库Vitamio的使用以及功能扩展
  16. 最新常用数据库排名及分类介绍
  17. 如何利用英特尔管理工具绕过Windows防火墙
  18. 游戏模拟器成了外挂帮凶,灰产对抗再升级
  19. 装修颜色搭配方案,打造与众不同的家居
  20. 系统集成十大项目管理(1)

热门文章

  1. Javascript自定义事件功能与用法实例分析
  2. mysql的高级特性
  3. 关于vmware workstation10常见问题
  4. Mysql存储引擎MyIsAM和InnoDB区别
  5. u3d中texture2D的Advanced设置解析
  6. ajax-典型应用-验证用户名
  7. css3毛玻璃模糊效果
  8. UVa 537 - Artificial Intelligence?
  9. P1462 通往奥格瑞玛的道路[最短路+二分+堆优化]
  10. python 面向对象(三大特性)