• 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一个爱称-我佩服。于我而言,耗费一周的时间,最后发现,我研究的技术居然如此白痴-我喷饭!

  • 相关阅读:
    MVC4中Ajax.BeginForm OnSuccess 不执行以及控制器返回JsonResult 提示下载的原因
    string.Equals 比较2个字符串是否相同忽略大小写
    [转载]mvc使用JsonResult返回Json数据
    [转载]深入理解ASP.NET MVC之ActionResult
    [转载]自定义ASP.NET MVC Html辅助方法 TagBuilder
    [转载]AOP面向方面编程
    [转载]ASP.NET MVC 3的分部视图
    适配 iOS尺寸
    IOS Bug分析
    苹果一些乱七八糟流程整理
  • 原文地址:https://www.cnblogs.com/ww960122/p/4591850.html
Copyright © 2020-2023  润新知