草庐IT

WPF学习笔记06-依赖属性DependencyProperty

IceAmos 2023-03-28 原文

在学习依赖属性之前,我们首先要知道属性是什么?属性呢其实就是为了保护数据!避免数据直接暴漏给外界。什么是依赖属性呢?依赖属性和属性又有什么区别呢?依赖属性是一种可以自己没有值,并能通过使用Binding从数据源获得值的属性。言简意赅,就是依靠着别人赋值的属性。至于区别是什么,我们接下来说完依赖属性之后也许你就会多多少少理解一点了!

1 - 了解依赖属性

首先,我们需要先了解下依赖属性,依赖属性和普通属性的用法其实是一样的,在之前的Demo中我们每个Demo都有用到依赖属性只不过你不知道而已,比如Background="Blue"这个Background就是一个属性并且是一个DependencyProperty也就是依赖属性。

依赖属性其实就是专门针对WPF而创建的。但是呢,我们使用的时候会没有任何感觉,是因为WPF库都使用了普通属性进行了封装,这个之后我们也会介绍到一个概念(包装器)所以我们也能够常规的去使用它了。其实当我们回头看我们写过的代码的时候,每个属性F12之后你都能看到对应的声明基本上都包含了一个词DependencyProperty

可能现在只通过文字去描述依赖属性你还是不太理解。那咱们接下来往下看。

2 - 使用依赖属性

2.1 - 定义依赖属性

其实依赖属性在我们实际开发过程中,很多时候我们都仅仅是使用它,但是对于一些特殊的场景比如我们创建的自定义用户控件等情况下我们还是会要用到的。

首先定义依赖属性的前提是,对应的对象也就是所属类必须继承于DependencyObject依赖对象。在WPF中我们使用的时候没感觉是因为大多数你一直F12之后最后都能发现继承于DependencyObject。

依赖属性定义:

public static readonly DependencyProperty xxxxProperty;

依赖属性的结尾根据WPF定义的规则必须是以Property结尾的,且需要为静态只读。

2.2 - 注册依赖属性

注册依赖函数,需要在任何可能使用到依赖属性之前完成,因此必须要在关联的静态构造函数中进行。在WPF的机制当中,DependencyProperty是不能被直接实例化的。因为DependencyProperty没有公有构造函数。只能通过DependencyProperty.Regsiter()方法进行注册从而完成实例。并且还需要确认一件事就是创建后不被改变该对象这也就是为什么所有的都是是只读的。

注册依赖属性

TestProperty =
            DependencyProperty.Register("MyProperty", typeof(int), typeof(MainWindow), new PropertyMetadata(0));

调用Register时需要传入几个参数

1)属性名

2)属性使用的类型

3)拥有该属性的所属类型

4)PropertyMetadata对象【可选】

5)验证属性的回调函数ValidateValueCallback【可选】

前三个必填项比较显而易见,不过多赘述,接下来介绍下PropertyMetadata和ValidateValueCallback

2.2.1 - PropertyMetadata

PropertyMetadata一共有五个重载

public PropertyMetadata()
{
}

public PropertyMetadata(object defaultValue)
{
DefaultValue = defaultValue;
}

public PropertyMetadata(PropertyChangedCallback propertyChangedCallback)
{
PropertyChangedCallback = propertyChangedCallback;
}

public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback)
{
DefaultValue = defaultValue;
PropertyChangedCallback = propertyChangedCallback;
}

public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback)
{
DefaultValue = defaultValue;
PropertyChangedCallback = propertyChangedCallback;
CoerceValueCallback = coerceValueCallback;
}

1) 空的

2)默认值【类型需和所声明的类型一致】

new PropertyMetadata(默认值【类型需要和所声明的一直】)

3)PropertyChangedCallback

propertyMetadata.PropertyChangedCallback = ((s, e) =>
{
    Debug.WriteLine(String.Format("PropertyChanged - 属性:{0} 新值:{1} 旧值:{2}", e.Property.Name, e.NewValue, e.OldValue));
});

4) CoerceValueCallback

propertyMetadata.CoerceValueCallback = (s, e) =>
{
    Debug.WriteLine(String.Format("CoerceValue - {0}", e));
    return e;
};

2.2.2 - ValidateValueCallback

(o) => {
    Brush brush = o as Brush;
    if (brush== Brushes.Yellow||brush== Brushes.Blue)
    {
        return true;
    }
    else
    {
        return false;
    }
}

比如上边判断如果为黄色或者蓝色才可以,其他颜色都不可以。如果我们前台赋值为Orange时则会提示

在接下来我们会着重介绍对应的使用方式

2.3 - 属性包装器

当我们创建完成之后,最后一部就是用传统的.Net属性封装的方法进行封装。但是唯一不同的是依赖属性使用的是GetValue()和SetValue()方法

//属性包装器
public Brush MyColor
{
    get { return (Brush)GetValue(MyColorProperty); }
    set { SetValue(MyColorProperty, value); }
}

之后的话,我们使用依赖属性就和使用普通属性那样去使用就行了。

3 - 依赖属性优先级

依赖属性依赖于多个属性提供者。每个提供者都有对应的优先级。对应的优先级顺序【由低到高】如下

    1. 默认值(也就是PropertyMetadata中的defaultValue)
    2. 继承而来的值
    3. 主题样式的值
    4. 项目样式的值
    5. 本地值

WPF中按照对应优先级确定依赖属性的基本知识,但是基本知识不一定就是最后从属性中检索到的值,因为WPF还需要考虑一些其他因素。

WPF中决定属性值的步骤(四部)

1)确认基本值

2)如果属性是使用表达式设置的,就怼表达式进行求值。当前支持两类表达式【数据绑定】【资源】

3)如果属性是动画目标就应用动画

4)运行强制转换回调函数来修正属性值

4 - 附加属性

附加属性就是依赖属性的一个附加。比如Grid容器分为行和列,当我们分别往对应行列放置控件时。需要设置对应的Grid.Row和Grid.Column。其中Row和Column就是对应的附加属性。

自定义的附加依赖属性和依赖属性唯一区别就是对应的注册方式不一样。依赖属性调用的是Register,附加依赖属性是用的RegisterAttached。

我们直接上代码

//声明
public static readonly DependencyProperty MyBgColorProperty;
static MyButton()
{
     MyBgColorProperty =
                DependencyProperty.RegisterAttached("MyBgColor", typeof(Brush), typeof(MyButton), propertyMetadata);
}
//属性包装器
public Brush MyBgColor
{
    get { return (Brush)GetValue(MyBgColorProperty); }
    set { SetValue(MyBgColorProperty, value); }
}

界面使用

<UserControl
    x:Class="FourthWPFDemo.MyButton"
    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:FourthWPFDemo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Name="uc"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <Grid>
        <Button
            Background="{Binding ElementName=uc, Path=MyColor}"
            BorderBrush="{Binding ElementName=uc, Path=MyBgColor}"
            BorderThickness="3" />
    </Grid>
</UserControl>
<Window
    x:Class="FourthWPFDemo.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:FourthWPFDemo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <StackPanel>
        <local:MyButton
            Width="120"
            Height="30"
            Margin="0,30"
            MyColor="LightSkyBlue">
            <local:MyButton.MyBgColor>
                <SolidColorBrush Color="Pink" />
            </local:MyButton.MyBgColor>
        </local:MyButton>
    </StackPanel>
</Window>

至此,依赖属性的简单使用基本就学习完了

有关WPF学习笔记06-依赖属性DependencyProperty的更多相关文章

  1. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  2. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  3. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  4. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  6. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  10. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

随机推荐