WPF学习(四) - 附加属性

  冷静了一晚,我就当这次学习的过程是在看狗血剧情的武打小说吧:没有垃圾的武术,只有垃圾的武者……

  还有个话儿怎么说来着:你们是用户,不是客户,也就有个使用的权力。搞清楚身份,别叽叽歪歪的!

  没办法,全世界都说好的东西,我也得从善,继续学习。

  从用法的角度来看,附加属性与依赖属性有所不同。

  定义依赖属性,是为了满足绑定技术的要求,实现对象间的数据同步的目的。

  而附加属性,是为了实现其他对象具有我的某些属性这个目的。

  第一次看到附加属性的应用,是在XAML文档中出现的。

  <Window>
    <Grid>
      <Button x:Name = "btn1" Grid.Row = "1"/>
    </Grid>
  </Window>

  Button,本身没有布局关系的属性,外层的Grid了一些布局关系属性,Button只要引用过来,就可以给自己重新定位,多么神奇的实现!

  附加属性的意思是:我定义的特征可以让别人拿去修饰他自己。换个说法,别人拿了我的牲征,作为他的附加属性来描述自己。

  这里,把“我”定义个名称叫做宿主,“别人”叫做订购者,实现一个简单的附加属性的用例。

    class HostObject : DependencyObject
    {

        public static string GetAttachedText ( DependencyObject obj )
        {
            return ( string ) obj.GetValue ( AttachedTextProperty );
        }

        public static void SetAttachedText ( DependencyObject obj, string value )
        {
            obj.SetValue ( AttachedTextProperty, value );
        }

        // 我觉得这种属性应该叫签证,注册的过程就是登记
        public static readonly DependencyProperty AttachedTextProperty =
            DependencyProperty.RegisterAttached ( "AttachedText", typeof ( string ), typeof ( HostObject ));

    }

定义宿主

    class Order : DependencyObject
    {
    }

定义订购者

        public static void TestAttachedProperty ( )
        {
            //规规矩矩的用法,从宿主存取值
            Order a = new Order ( );
            HostObject.SetAttachedText ( a, "aaaa" );
            Console.WriteLine ( HostObject.GetAttachedText ( a ) );

            //再来一次,两个对象各自存取自己的值
            Order b = new Order ( );
            HostObject.SetAttachedText ( b, "bbbb" );
            Console.WriteLine ( HostObject.GetAttachedText ( b ) );
        }

测试用例

  可以看到,宿主和订购者的类之间没有任何的关系。

  从表现形式上看,宿主提供GetAttachedText和SetAttachedText方法,允许订购者订购自己的专用寄存器,最终看起来订购者具备一些额外的属性。细看这两个方法的实现过程,其实是由订购者自己来调用GetValue和SetValue方法,达到存/取值的目的,而不是宿主来做这些事儿。

  通过前日的学习,我已知道,附加属性存储值的地方既不在宿主中,也不在订购者中,而是用另外的一个容器统一管理。

  使用附加属性的对象都要求从DependencyObject派生,这样就自带GetValue和SetValue方法,可以从容器里存取数据了。

  宿主给自己包上一层糖衣,实现GetAttachedText和SetAttachedText方法,表现成从宿主对象上,可以存取订购者的附加属性。

  我们也可以从订购者处,存取附加属性

        public static void TestAttachedProperty2 ( )
        {
            Order c = new Order ( );
            c.SetValue ( HostObject.AttachedTextProperty, "cccc" );
            string value = ( string ) c.GetValue ( HostObject.AttachedTextProperty );
            Console.WriteLine ( value );
        }

从订购者存取值

  我可以更放纵一点

        public static void TestAttachedProperty3 ( )
        {

            DependencyProperty MyAttachedVisa = DependencyProperty.RegisterAttached ( "MyAttachedRegisterName", typeof ( string ), typeof ( SimpleClass ) );
            Order d = new Order ( );
            d.SetValue ( MyAttachedVisa, "Hello MyAttachedRegister" );
            string value2 = ( string ) d.GetValue ( MyAttachedVisa );
            Console.WriteLine ( value2 );
        }

直接从附加属性存取数据

  看来,只要类是从DependencyObject派生的,它的对象都可以向容器里伸把手。

  回头再想想最前面那个神奇的Button和Grid,如何实现布局的呢?抛开看不到原理的静态快照,用代码来实现。

        public WindowTestAttachedProperty ( )
        {
            InitializeComponent ( );

            Grid grid = new Grid ( );

            grid.ColumnDefinitions.Add ( new ColumnDefinition ( ) );
            grid.ColumnDefinitions.Add ( new ColumnDefinition ( ) );
            grid.ColumnDefinitions.Add ( new ColumnDefinition ( ) );

            Button button = new Button ( );
            //可以用宿主的静态方法来设置
            Grid.SetColumn ( button, 1 );
            //也可以用订购者的实例方法来设置
            button.SetValue ( Grid.ColumnProperty, 1 );

            grid.Children.Add ( button );
            this.Content = grid;
        }

代码实现附加属性调用

  那个神奇的现象在这里实现:grid.Children.Add ( button );

  布局对象先达好架子,为将来可能来到的子对象定义好区域。每个子对象被加入时,就给子对象分配位置。

  这个逻辑很简单,子对象中与布局相关的附加属性定义好后,在布局对象调用AddChildren方法时,

  这些属性值同样可以被布局对象获取到。那么用这些值去分配位置就好了。

  开辟一个容器,让宿主和订购者都可以存取里面的数据,就是这么一个技巧,被WPF做为核心技术,展示出众多神奇的现象。

  实际上却是要程序员放弃结构设计的原创权力,调用大量似是而非的糖衣,程序员做的事儿只是看上去象那么回事儿而已。

  崇拜它,你就永远也不知道它其实有多么普通。WPF用最白痴的技巧实现了-灵活与自由!

  有人送给WPF一个爱称-我佩服。于我而言,耗费一周的时间,最后发现,我研究的技术居然如此白痴-我喷饭!

时间: 2024-10-28 11:43:28

WPF学习(四) - 附加属性的相关文章

【WPF学习】第二十四章 基于范围的控件

原文:[WPF学习]第二十四章 基于范围的控件 WPF提供了三个使用范围概念的控件.这些控件使用在特定最小值和最大值之间的数值.这些控件--ScrollBar.ProgressBar以及Slider--都继承自RangeBase类(该类又继承自Control类).尽管它们使用相同的抽象概念(范围),但工作方式却又很大的区别. 下表显示了RangeBase类定义的属性: 表 RangeBase类的属性 通常不比直接使用ScrollBar控件.更高级的ScrollViewer控件(封装了两个Scro

【WPF学习】第十四章 事件路由

原文:[WPF学习]第十四章 事件路由 由上一章可知,WPF中的许多控件都是内容控件,而内容控件可包含任何类型以及大量的嵌套内容.例如,可构建包含图形的按钮,创建混合了文本和图片内容的标签,或者为了实现滚动或折叠的显示效果而在特定容器中放置内容.设置可以多次重复嵌套,直至达到你所希望的层次深度.如下所示: <Window x:Class="RouteEvent.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2

【WPF学习】第四十四章 图画

原文:[WPF学习]第四十四章 图画 通过上一章的学习,Geometry抽象类表示形状或路径.Drawing抽象类扮演了互补的角色,它表示2D图画(Drawing)--换句话说,它包含了显示矢量图像或位图需要的所有信息. 尽管有几类画图类,但只有GeometryDrawing类能使用已经学习过的几何图形.它增加了决定如何绘制图形的画笔和填充细节.可将GeometryDrawing对象视为矢量插图中的形状.例如,可将标准的窗口元文件格式(.wmf)转换成准备插入用户界面的GeometryDrawi

8 WPF学习之深入浅出话属性

转载:http://blog.csdn.net/fwj380891124/article/details/8131080 通过前面的学习,我们已经知道Data Binding是WPF"数据驱动UI"理念的基础.上一章我们将主要的精力放在了Binding的数据源这一端,研究了Binding的Source和Path.本章我们将把目光移向Binding的目标端,研究一下什么样的对象才能作为Binding的Target以及Binding将把数据送往何处. 1.1      属性(Propert

【WPF学习】第二十九章 元素绑定——将元素绑定到一起

原文:[WPF学习]第二十九章 元素绑定--将元素绑定到一起 数据banding的最简单情形是,源对象时WPF元素而且源属性是依赖性属性.前面章节解释过,依赖项属性具有内置的更改通知支持.因此,当在源对象中改变依赖项属性的值时,会立即更新目标对象中的绑定属性.这正是我们所需要的行为--而且不必为此构建任何额外的基础结构. 为理解如何将一个元素绑定到另一个元素,下面创建一个简单的示例.该示例窗口包含了两个控件:一个Slider控件和一个具有单行文本的TextBlock控件.如果向右拖动滑动条上的滑

【WPF学习】第二十章 内容控件

原文:[WPF学习]第二十章 内容控件 内容控件(content control)是更特殊的控件类型,它们可包含并显示一块内容.从技术角度看,内容控件时可以包含单个嵌套元素的控件.与布局容器不同的是,内容控件只能包含一个子元素,而布局容器主要愿意可以包含任意多个牵头元素. 正如前面所介绍,所有WPF布局容器都继承自抽象类Panel,该类提供了对包含多个元素的支持.类似地,所有内容控件都继承自抽象类ContentControl.下图显示了ContentControl类的层次结构. 图 Conten

【WPF学习】第三十二章 执行命令

原文:[WPF学习]第三十二章 执行命令 前面章节已经对命令进行了深入分析,分析了基类和接口以及WPF提供的命令库.但尚未例举任何使用这些命令的例子. 如前所述,RoutedUICommand类没有任何硬编码的功能,而是只表达命令,为触发命令,需要有命令源(也可使用代码).为响应命令,需要有命令绑定,命令绑定将执行转发给普遍的事件处理程序. 一.命令源 命令库中的命令始终可用.触发他们的最简单的方法是将它们关联到实现了ICommandSource接口的控件,其中包括继承自ButtonBase类的

WPF学习------XAML 语法详述

XAML 语言规范 XAML 语言规范中也定义或引用了此处定义的 XAML 语法术语. XAML 是一种基于 XML 并遵循或扩展 XML 结构规则的语言. 其中某些术语共享自或基于描述 XML 语言或 XML 文档对象模型时常用的术语. 有关 XAML 语言规范的更多信息,请从 Microsoft 下载中心下载 [MS-XAML]. XAML 和 CLR XAML 是一种标记语言. 顾名思义,公共语言运行时 (CLR) 实现了运行时执行. XAML 本身并非 CLR 运行时直接使用的一种公共语

WPF学习开发客户端软件-任务助手

本人纯属WPF新手,布局和WPF的开发水平相当欠缺,从个人来说,还是比较喜欢WPF的,有人说WPF是界面加上WINFORM,我不这样认为,WPF与WINFORM主要的不同在于数据绑定. 这个软件虽然功能比较简单,没有做分层设计,也没有使用MVVM的开发模式,但也确实花了我不少的时间,算是这段时间学习WPF的结果吧,在此给大家展示一下,也给同行的新手门一个参考的例子(喜欢不会是误导). 软件具体功能如下: 1.本软件可以设置计划任务运行的周期:一次.每月.每天.每小时.间隔分钟等不种不同的运行模式

WPF学习笔记2&mdash;&mdash;XAML之2

三.事件处理程序与代码隐藏 例如,为一个Page添加一个Button控件,并为该Button添加事件名称Button_Click: <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ExampleNamespace.ExampleP