本文想通过由浅入深的讲解让读者比较深的理解依赖属性.  首先,我们回顾一下依赖属性的发展历史.

最初,人们提出面向对象编程时,并没有属性这个说法,当时叫做成员变量.一个对象由成员变量和成员函数组成,如下:

Public Class A{
Public int Index;//成员变量
Public void Fun(){} //成员函数
} 

后来,提出了对成员变量的改进,增加了get/set 方法,成员变量自然也叫属性了。.net采用了这种方法:

Public Class A{
      Private int index;//属性
   Public  int Index{
        Set{index = Value;}
        Get{return index ;}
     }
   Public void Fun(){} //方法
}

到了WPF, 终于变成依赖属性(WPF大部分属性都是依赖属性)。我们先看一个依赖属性的实现,再理解。

public partial class MyButton : Button {
       public static DependencyProperty PressedImageProperty;//依赖属性
 
       public string PressedImage {
           get { return (string)GetValue(PressedImageProperty); }
           set { SetValue(PressedImageProperty, value); }
       }
 
       static MyButton() {
           PressedImageProperty = DependencyProperty.Register(
               "PressedImage", typeof(string), typeof(MyButton),
               new FrameworkPropertyMetadata(""));
       }
 
       public MyButton () {
           InitializeComponent();
       }

上面实现了一个PressedImage的依赖属性。和.net属性比较有几点区别:

1。依赖属性的实体是静态的,类型为DependencyProperty。

如上例中的属性PressedImage,如果在.net中会这样定义它的实体

public string pressedImage;

依赖属性却是这样:

public static DependencyProperty PressedImageProperty;

2。多了一个Register。

3. 它的Get/Set方法借助DependencyObject的GetValue/SetValue来实现.

但凭这些区别是没法理解依赖属性,因为你不知道DependencyProperty,DependencyObject怎么实现的.这里我只能说一下依赖属性一个特点:

在面向对象编程时,一个对象有自己的各种属性,我们以往创建一个对象时,它的属性值就保存在对象本身.但依赖属性却不是把属性值保存在对象本身,而是保存在一张公共的依赖属性表里,它包含所有对象的依赖属性.因此,当我们要知道一个对象的某个属性时,WPF不是从该对象直接取出,而是从那张公共的依赖属性表里取出.

呵呵,大概你明白了为什么依赖属性会变得复杂起来.实际上,功能也强大得多.

下面就来讨论自定义依赖属性和它的数据绑定.

通过例子说明。对上文MyButton进行修进,实现以下功能:当MyButton被按下时显示图片"c:\images\ButtonPressed.png",否则显示图片"c:\images\ButtonNormal.png".   xaml代码

<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image x:Name="imgNormal"
Source="c:\images\ButtonNormal.png" Visibility="Visible"/>
<Image x:Name="imgPressed"
Source="c:\images\ButtonPressed.png" Visibility="Hidden" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="imgNormal" Property="Visibility" Value="Hidden"/>
<Setter TargetName="imgPressed" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>

  cs文件代码:

public partial class MyButton : Button {
      
       public MyButton () {
           InitializeComponent();
       }

上面的代码看不懂也没关系,并没有用到依赖属性。 但同时,这个MyButton并没有使用价值,因为他的图片是固定的。我们希望MyButton的图片可以由用户来设定。在上面的xaml文件中,只需改变Image的Source属性。WPF的方法就是数据绑定,也就是把Image的Source属性绑定到一个变量,修改一下xaml:

<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
     <Grid>      
<Image x:Name="imgNormal" Source="{Binding Path=NormalImage}" Visibility="Visible"/>
     <Image x:Name="imgPressed" Source="{Binding Path=PressedImage}" Visibility="Hidden" />
     </Grid>    
<ControlTemplate.Triggers>      
<Trigger Property="IsPressed" Value="True">
          <Setter TargetName="imgNormal" Property="Visibility" Value="Hidden"/>
          <Setter TargetName="imgPressed" Property="Visibility" Value="Visible"/>
       </Trigger>    
</ControlTemplate.Triggers>  
</ControlTemplate>
</Button.Template>

imgNormal的图片路径绑定变量NormalImage, imgPressed的图片路径绑定到PressedImage,再在MyButton类中增加2个属性NormalImage,PressedImage

 public partial class MyButton : Button {
public string NormalImage;
           public   string NormalImage;
            public MyButton () {
InitializeComponent();
}

在使用MyButton时用以下语句访问:

<my:MyButton NormalImage="c:\images\ButtonNormal.png" 
 PressedImage="c:\images\ButtonPressed.png" />

   搞定!!怎么?编译通不过?因为NormalImage和PressedImage不是依赖属性,所以编译无法通过。 那就继续改吧,把NormalImage和PressedImage改成依赖属性。

MyButton.cs的最后代码如下:

public partial class MyButton : Button {
       public static DependencyProperty NormalImageProperty;
       public static DependencyProperty PressedImageProperty;
 
       public string NormalImage {
           get { return (string)GetValue(NormalImageProperty); }
           set { SetValue(NormalImageProperty, value); }
       }
 
       public string PressedImage {
           get { return (string)GetValue(PressedImageProperty); }
           set { SetValue(PressedImageProperty, value); }
       }
 
       static MyButton () {
           NormalImageProperty = DependencyProperty.Register(
               "NormalImage", typeof(string), typeof(MyButton ),
               new FrameworkPropertyMetadata(""));
 
           PressedImageProperty = DependencyProperty.Register(
               "PressedImage", typeof(string), typeof(MyButton ),
               new FrameworkPropertyMetadata(""));
       }
 
       public MyButton () {
           InitializeComponent();
       }

为什么xaml不支持普通属性?

回顾一下WPF的基本理念:真正做到了分离界面设计人员与开发人员的工作。也就是说,xaml文件呈现的是用户界面,从xaml到用户界面的转化不是由编译器直接编译成用户界面的运行代码(这样和原来的WIN FORM又没有区别了),而是由WPF本身类库来来完成的,打个比方,XAML有如下代码:

<Button Background="White"></Button>

其中的“White”是如何与C#中的System.Windows.Media.Brushes.White等价的呢?。原来WPF提供了Brush数据类型的转换器。

对于简单属性(如int类型的), WPF要解释它并不难,如果是自定义类型的呢,WPF要解释它也不难,比如要求开发人员在使用自定义类型的属性时,同时提供该自定义类型的转换器。因此,个人认为,xaml不支持普通属性的原因就是WPF的设计者认为没有必要。

 
 

WPF学习笔记一 依赖属性及其数据绑定的更多相关文章

  1. WPF学习笔记二 依赖属性实现原理及性能分析

    在这里讨论依赖属性实现原理,目的只是学习WPF是怎么设计依赖属性的,同时更好的使用依赖属性. 首先我们来思考一个简单的问题:我们希望能验证属性的值是否有效,属性变更时进行自己的处理.回顾一下.net的 ...

  2. WPF 学习笔记-设置属性使窗口不可改变大小

    原文:WPF 学习笔记-设置属性使窗口不可改变大小 调整Windows下的ResizeMode属性: ResizeMode = NoResize Resize属性是控制Windows是否可以改变大小, ...

  3. WPF学习笔记(一):数据绑定之元素到元素绑定

    前言 作为一只菜鸟,之前学了一段时间的WPF,但是没有总结,过了一学期发现好多东西都忘记了,很多东西还是需要记下来,以备后续复习. 数据绑定在事件中应用非常广泛,可以有效地减少代码量,那么什么是数据绑 ...

  4. WPF学习笔记:(二)数据绑定模式与INotifyPropertyChanged接口

    数据绑定模式共有四种:OneTime.OneWay.OneWayToSource和TwoWay,默认是TwoWay.一般来说,完成数据绑定要有三个要点:目标属性是依赖属性.绑定设置和实现了INotif ...

  5. WPF学习笔记:(一)数据绑定与DataContext

    前一段半心半意地学习了一下WPF,是从控件入手的,发现巨容易,甚至有些无趣.昨天面试,被问到了很多WPF的特性的东西,直接就傻了.于是乎,还是要去深刻的学习一下WPF.刚刚试了一下数据绑定,几次都没有 ...

  6. 【WPF学习笔记】之依赖属性

    概述: Windows Presentation Foundation (WPF) 提供了一组服务,这些服务可用于扩展公共语言运行时 (CLR) 属性的功能.这些服务通常统称为 WPF 属性系统.由 ...

  7. WPF 学习笔记-在WPF下创建托盘图标

    原文:WPF 学习笔记-在WPF下创建托盘图标 首先需要在项目中引用System.Windows.Forms,System.Drawing; using System; using System.Co ...

  8. Spring学习笔记之依赖的注解(2)

    Spring学习笔记之依赖的注解(2) 1.0 注解,不能单独存在,是Java中的一种类型 1.1 写注解 1.2 注解反射 2.0 spring的注解 spring的 @Controller@Com ...

  9. SpringMVC:学习笔记(11)——依赖注入与@Autowired

    SpringMVC:学习笔记(11)——依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...

随机推荐

  1. Spring总结之SpringMvc下

    五.拦截器 SpringMVC中的拦截器是通过HandlerInterceptor来实现的,定义一个Interceptor有两种方式 1.实现HandlerInterceptor接口或者继承实现了Ha ...

  2. Java 批量删除Word中的空白段落

    1. 测试文档.期望达到的目标文档效果 用于测试的Word文档如下所示,包含的空白段落影响文章整体布局及美观性: 目标文档效果: 2. 辅助工具 2.1 使用类库:Free Spire.Doc for ...

  3. Cookie学习总结

    Cookie简述 1. 概念 一种客户端会话技术,可以将一些少量的数据保存在客户端. 2. 快速使用 步骤 创建cookie对象,并设定数据 new Cookie(String name, Strin ...

  4. Dubbo的优雅下线原理分析

    文/朱季谦 Dubbo如何实现优雅下线? 这个问题困扰了我一阵,既然有优雅下线这种说法,那么,是否有非优雅下线的说法呢? 这,还真有. 可以从linux进程关闭说起,其实,我们经常使用到杀进程的指令背 ...

  5. NumPy之:多维数组中的线性代数

    目录 简介 图形加载和说明 图形的灰度 灰度图像的压缩 原始图像的压缩 总结 简介 本文将会以图表的形式为大家讲解怎么在NumPy中进行多维数据的线性代数运算. 多维数据的线性代数通常被用在图像处理的 ...

  6. [考试总结]noip模拟20

    第五场,再挂分就没了.. 然后就没了.. 考场上一直想方法. 似乎想到了 \(T1\) 正解. 然而几个 \(k\) 的调试信息都让我迷失了自我. 然后有几句啥都没用的语句加在了上面.. 挂分... ...

  7. PL SQL Developer 13连接Oracle数据库并导出数据

    下载 并安装 PL SQL Developer 13,默认支持中文语言 ============================= 注册码: product code: 4vkjwhfeh3ufnqn ...

  8. 如何用C++自己实现mysql数据库的连接池?

    为什么是mysql? 现在几乎所有的后台应用都要用到数据库,什么关系型的.非关系型的:正当关系的,不正当关系的:主流的和非主流的, 大到Oracle,小到sqlite,以及包括现在逐渐流行的基于物联网 ...

  9. anyRTC视频连麦demo上线啦!

    音频连麦demo一经问世就得到开发者的一致好评,有很多开发者咨询视频连麦的demo该怎么去实现,本着让"视频交付更简单"的理念,我们推出了视频连麦demo! 音视频技术不仅局限用于 ...

  10. CS229 斯坦福大学机器学习复习材料(数学基础) - 线性代数

    CS229 斯坦福大学机器学习复习材料(数学基础) - 线性代数 线性代数回顾与参考 1 基本概念和符号 1.1 基本符号 2 矩阵乘法 2.1 向量-向量乘法 2.2 矩阵-向量乘法 2.3 矩阵- ...