WPF(附加属性和依赖属性)

 附加属性的值可以被子元素继承

 我们一般定义一个附加属性会如下一样定义:

using System.Windows;
using System.Windows.Controls;

public class Test : Button
{

    public static int GetCount(DependencyObject obj)
    {
        return (int)obj.GetValue(CountProperty);
    }

    public static void SetCount(DependencyObject obj, int value)
    {
        obj.SetValue(CountProperty, value);
    }

    public static readonly DependencyProperty CountProperty =
        DependencyProperty.RegisterAttached("Count", typeof(int), typeof(Test),
            new PropertyMetadata(0));
}

这样定义并不会让子元素继承该属性 ,我们可以在注册时将PropertyMetadata改为其的派生类FrameworkPropertyMetadata,在FrameworkPropertyMetadata中有带FrameworkPropertyMetadataOptions类型参数的构造函数。

FrameworkPropertyMetadataOptions是个枚举类型:

        None = 0,未指定任何选项;依赖属性使用 Windows Presentation Foundation (WPF) 属性系统的默认行为。
        AffectsMeasure = 1,更改此依赖属性的值会影响布局组合的测量过程。
        AffectsArrange = 2,更改此依赖属性的值会影响布局组合的排列过程。
        AffectsParentMeasure = 4,更改此依赖属性的值会影响父元素上的测量过程。
        AffectsParentArrange = 8,更改此依赖属性的值会影响父元素上的排列过程。
        AffectsRender = 16,更改此依赖属性的值会影响呈现或布局组合的某一方面(不是测量或排列过程)。
        Inherits = 32,此依赖属性的值将由子元素继承。
        OverridesInheritanceBehavior = 64,此依赖属性的值跨越分隔的树以实现属性值继承。
        NotDataBindable = 128,不允许将数据绑定到此依赖属性。
        BindsTwoWayByDefault = 256,此依赖属性上的数据绑定的 System.Windows.Data.BindingMode 默认为 System.Windows.Data.BindingMode.TwoWay。
        Journal = 1024,此依赖属性的值应由日记记录进程或在由 Uniform resource identifiers (URIs) 导航时进行保存或存储。
        SubPropertiesDoNotAffectRender = 2048 此依赖属性值上的子属性不会影响呈现的任何方面。

所以我们如下注册附加属性就可以了: 

using System.Windows;
using System.Windows.Controls;

public class Test : Button
{

    public static int GetCount(DependencyObject obj)
    {
        return (int)obj.GetValue(CountProperty);
    }

    public static void SetCount(DependencyObject obj, int value)
    {
        obj.SetValue(CountProperty, value);
    }

    public static readonly DependencyProperty CountProperty =
        DependencyProperty.RegisterAttached("Count", typeof(int), typeof(Test),
            new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.Inherits));
}

一个属性即可作为依赖属性使用也可作为附加属性使用

 例如:TextBlock.FontSize

<Window x:Class="WpfApp3.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d">
    <Grid>
        <StackPanel TextBlock.FontSize="15">
            <TextBlock Text="TextBlock1" FontSize="12"/>
            <TextBlock Text="TextBlock1"/>
            <TextBlock Text="TextBlock1"/>
        </StackPanel>
    </Grid>
</Window>

那如何在代码中自定义一个类似这样的属性呢?作为初学者,一开始我也很迷惑。

通过F12查看FontSize的定义:

 //
 // 摘要:
 //     标识 System.Windows.Controls.TextBlock.FontSize 依赖属性。
 //
 // 返回结果:
 //     System.Windows.Controls.TextBlock.FontSize 依赖项属性的标识符。
 [CommonDependencyPropertyAttribute]
 public static readonly DependencyProperty FontSizeProperty;

//
// 摘要:
//     返回指定的依赖对象的 System.Windows.Controls.TextBlock.FontSize 附加属性值。
//
// 参数:
//   element:
//     要从中检索 System.Windows.Controls.TextBlock.FontSize 附加属性值的依赖对象。
//
// 返回结果:
//     System.Windows.Controls.TextBlock.FontSize 附加属性的当前值(位于指定的依赖对象上)。
//
// 异常:
//   T:System.ArgumentNullException:
//     element 为 null。
[TypeConverter(typeof(FontSizeConverter))]
public static double GetFontSize(DependencyObject element);

//
// 摘要:
//     设置指定的依赖对象上的 System.Windows.Controls.TextBlock.FontSize 附加属性值。
//
// 参数:
//   element:
//     要在其上设置 System.Windows.Controls.TextBlock.FontSize 属性值的依赖对象。
//
//   value:
//     要将此属性设为的新值。
//
// 异常:
//   T:System.ArgumentNullException:
//     element 为 null。
public static void SetFontSize(DependencyObject element, double value);

可以发现,即定义了FontSizeProperty依赖属性,又定义附加属性的Get和Set方法。

下面我们写个demo测试一下,根据上述的写法是否可行:

using System.Windows;
using System.Windows.Controls;

public class Test : Button
{

    public static int GetCount(DependencyObject obj)
    {
        return (int)obj.GetValue(CountProperty);
    }

    public static void SetCount(DependencyObject obj, int value)
    {
        obj.SetValue(CountProperty, value);
    }

    public static readonly DependencyProperty CountProperty =
        DependencyProperty.Register("Count", typeof(int), typeof(Test),
            new FrameworkPropertyMetadata(0,FrameworkPropertyMetadataOptions.Inherits));

    public int Count
    {
        get { return (int)GetValue(CountProperty); }
        set { SetValue(CountProperty, value); }
    }
}
<Window x:Class="WpfApp3.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d">
    <Grid>
        <StackPanel local:Test.Count="680">
            <local:Test Content="{Binding RelativeSource={RelativeSource Mode=Self},Path=Count}" />
        </StackPanel>
    </Grid>
</Window>

测试可以发现Content值并不是680,因为Count是注册成的依赖属性, 值不能被子元素继承。可以将其注册为附加属性就可以实现Content的值为父元素中定义的附加属性的值。

using System.Windows;
using System.Windows.Controls;

public class Test : Button
{

    public static int GetCount(DependencyObject obj)
    {
        return (int)obj.GetValue(CountProperty);
    }

    public static void SetCount(DependencyObject obj, int value)
    {
        obj.SetValue(CountProperty, value);
    }

    public static readonly DependencyProperty CountProperty =
        DependencyProperty.RegisterAttached("Count", typeof(int), typeof(Test),
            new FrameworkPropertyMetadata(0,FrameworkPropertyMetadataOptions.Inherits));

    public int Count
    {
        get { return (int)GetValue(CountProperty); }
        set { SetValue(CountProperty, value); }
    }
}

通过查看TextBlock的源代码也可以知道,其实FontSize是注册为附加属性的。 

/// <summary>
/// DependencyProperty for <see cref="FontSize" /> property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontSizeProperty =
        TextElement.FontSizeProperty.AddOwner(
                typeof(TextBlock));


/// <summary>
/// DependencyProperty for <see cref="FontSize" /> property.
/// </summary>
[CommonDependencyProperty]
public static readonly DependencyProperty FontSizeProperty =
        DependencyProperty.RegisterAttached(
                "FontSize",
                typeof(double),
                typeof(TextElement),
                new FrameworkPropertyMetadata(
                        SystemFonts.MessageFontSize,
                        FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits),
                new ValidateValueCallback(IsValidFontSize));

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bridge_go

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值