代码改变世界

无废话WPF系列12: 依赖属性和附加属性

2011-02-27 11:09  敏捷的水  阅读(3366)  评论(0编辑  收藏  举报

一、依赖属性

依赖属性就是自己自己没有值,通过Binding从数据源获得值,就是依赖在别人身上,拥有依赖属性的对象称为依赖对象。

几种应用依赖属性的场景:

1. 希望可在样式中设置属性。

2. 希望属性支持数据绑定。

3. 希望可使用动态资源引用设置属性。

4. 希望从元素树中的父元素自动继承属性值。

5. 希望属性可进行动画处理。

6. 希望属性系统在属性系统、环境或用户执行的操作或者读取并使用样式更改了属性以前的值时报告。

7. 希望使用已建立的、WPF 进程也使用的元数据约定,例如报告更改属性值时是否要求布局系统重新编写元素的可视化对象。

依赖对象创建时并不包含存储数据空间。WPF中必须使用依赖对象作为依赖属性的宿主。

 

声明和使用依赖属性

提示:创建依赖属性时可以使用代码片段propdp

XAML

 

<Window x:Class="DeepXAML.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DeepXAML"       
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="250" Width="450">
    <StackPanel x:Name="stackPanel">
        <TextBox x:Name="textBox1" Margin="10"  Text="{Binding Path=Title}"></TextBox>
        <TextBox x:Name="textBox2" Margin="10" Text="{Binding Path=Title}"></TextBox>
    </StackPanel>
</Window>

后台代码
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;

namespace DeepXAML
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Game game = new Game { Title = "WarCraft" };
            this.stackPanel.DataContext = game;
        }
    }

    public class Game:DependencyObject
    {
        public string Title
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(Game));        
    }  
}

DependencyProperty.Register方法解释

a.第一个参数指明以哪个CLR属性作为依赖属性的包装

b. 第二参数指明依赖属性存期什么类型的值

c. 此依赖属性宿主的类型。

依赖属性的值存在哪里?

在WPF运行时,维护了一个全局的Hashtable存取依赖属性的值。

 

二、附加属性

附加属性就是自己没有这个属性,在某些上下文中需要就被附加上去。比如TextBox的Grid.Row属性,如果我们定义TextBox类时定义一个Row属性是没有意义的,因为我们并不知道一定会放在Grid里,这样就造成了浪费。

 

<Window x:Class="DeepXAML.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DeepXAML"       
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="250" Width="450">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0"></TextBox>
        <TextBox Grid.Row="1"></TextBox>
    </Grid>
</Window>

实际上在编译后,Grid.Row会在Grid的类里生成SetRow方法,Grid来调整控件的控制。也就是附加属性会生成方法,不会占用内存空间。

public class GameAP : DependencyObject
{
    public static int GetName(DependencyObject obj)
    {
        return (int)obj.GetValue(NameProperty);
    }

    public static void SetName(DependencyObject obj, int value)
    {
        obj.SetValue(NameProperty, value);
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NameProperty =
        DependencyProperty.RegisterAttached("Name", typeof(int), typeof(GameAP), new UIPropertyMetadata(0));
    
}