WPF MVVM入门系列教程(二、依赖属性)
说明:本文是介绍WPF中的依赖属性功能,如果对依赖属性已经有了解了,可以浏览后面的文章。
为什么要介绍依赖属性
在WPF的数据绑定中,密不可分的就是依赖属性。而MVVM又是跟数据绑定紧密相连的,所以在学习MVVM之前,很有必要先学习一下依赖属性。
依赖属性(Depencency Property)是什么
先来看看MSDN上的解释:
WPF提供一组服务,这些服务可用于扩展类型的属性的功能。 这些服务统称为 WPF 属性系统。 由 WPF 属性系统提供支持的属性称为依赖属性。
通俗点来说,WPF的依赖属性就是在.NET属性的基础上进行的扩展。它除了具备.NET属性的功能之外,还具备一些其它的扩展功能,如:值验证、默认值、值修改时的回调、转换器等。
我们先来看看.NET属性,也就是平常我们在C#中使用的属性
1 public class CLRProperty2 {3 private int id;4 5 public int Id6 {7 get => id;8 set => id = value;9 }
10 }
再来看看依赖属性
以Button控件的Content属性为例
1 public static readonly DependencyProperty ContentProperty = = DependencyProperty.Register("Content", typeof(object), typeof(ContentControl), new FrameworkPropertyMetadata((object)null, (PropertyChangedCallback)OnContentChanged));2 3 public object Content4 {5 get6 {7 return GetValue(ContentProperty);8 }9 set
10 {
11 SetValue(ContentProperty, value);
12 }
13 }
可以看到它也有一个get和set(即.NET的属性包装器),但是没有私有变量,而是通过GetValue和SetValue来完成取值和赋值。
依赖属性在使用上依赖属性和.NET属性无异:
例如有一个Button控件,命名为btn_Ok,我们可以在XAML中直接设置依赖属性的值
1 <Button Name="btn_Ok" Content="HelloWorld"></Button>
也可以在后台代码中设置
1 btn_Ok.Content = "HelloWorld";
如何创建依赖属性
大多数在使用WPF原生控件的情况下,我们都是使用依赖属性,而非创建它。但是在自定义控件时,可能会需要用到依赖属性功能。
依赖属性对象不能直接被实例化,因为它没有公开的构造函数,只能通过DependencyProperty.Register()方法创建实例。
我们这里以自定义一个MyButton控件为例。
1、定义表示属性的对象
注意:这里使用了static readonly关键字,且对象命名时,后面都加上Property。
1 public static readonly DependencyObject ImageProperty;
2、注册依赖属性
1 ImageProperty = DependencyProperty.Register("Image", typeof(ImageSource), typeof(MyButton),new PropertyMetadata(null, OnImagePropertyChanged));
DependencyProperty.Register函数支持多种重载,下面这是一种比较常用的重载。
1 public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);
下面来介绍一下它各个参数的作用
name:这个参数用于指定.NET属性包装器的名称
propertyType:指明依赖项属性存储什么类型的值,这里是ImageSource类型,代表图像数据
ownerType:指明此依赖属性的宿主是什么类型,这里是MyButton
typemetaData:指定此依赖属性的元数据,元数据定义依赖属性在应用于特定类型时的某些行为方面,包括默认值、值更改时的回调等。上面的代码中,typeMetadata的第一个参数代表依赖属性的默认值,设置为null,第二个参数是在值更改时的回调函数,这里是调用OnImagePropertyChanged函数。
3、添加属性包装器
1 public ImageSource Image
2 {
3 get => (ImageSource)GetValue(ImageProperty);
4 set => SetValue(ImageProperty, value);
5 }
4、使用依赖属性
XAML
1 <local:MyButton x:Name="btn_Ok" Image="logo.jpg"/>
后台代码
1 this.btn_Ok.Image = new BitmapImage(new Uri("logo.jpg", UriKind.Relative));
附加属性(Attached Property)
附加属性是一种特殊的依赖属性。
来看看MSDN上的解释:
附加属性是一个 XAML概念。 附加属性允许为派生自 DependencyObject 的任何 XAML 元素设置额外的属性/值对,即使该元素未在其对象模型中定义这些额外的属性。 额外的属性可进行全局访问。 附加属性通常定义为没有常规属性包装器的依赖属性的专用形式。
通俗点来说,就是这个属性并不属于某个元素,但是通过附加属性可以设置上去。
附加属性在定义时是被定义到应用的那个类,而非使用附加属性的那个类。
一个简单的例子,例如一个Button控件在被设计出来以后,设计者也不知道它以后会被用于哪个布局容器,可能是Canvas,也可能 是Grid。
这个时候附加属性的作用就体现出来了:
当这个Button被放在Grid里时,就为它附加上Grid.Row和Grid.Column属性。
当这个Button被放在Canvas里时,就为它附加上Canvas.Left和Canvas.Top属性。
所以Grid.Row和Column是定义在Grid类中,而Canvas.Left和Canvas.Top是被定义在Canvas中。这一点跟前面的依赖属性有区别。
下面我们看一下附加属性代码结构,以Grid.Row为例
Grid.Row附加属性的定义如下:
1 public static readonly DependencyProperty RowProperty = DependencyProperty.RegisterAttached("Row", typeof(int), typeof(Grid), new FrameworkPropertyMetadata(0, OnCellAttachedPropertyChanged), IsIntValueNotNegative);2 3 public static int GetRow(UIElement element)4 {5 if (element == null)6 {7 throw new ArgumentNullException("element");8 }9
10 return (int)element.GetValue(RowProperty);
11 }
12
13 public static void SetRow(UIElement element, int value)
14 {
15 if (element == null)
16 {
17 throw new ArgumentNullException("element");
18 }
19
20 element.SetValue(RowProperty, value);
21 }
如何创建附加属性
这里我们以为每个控件增加一个Id依赖属性为例,这个属性仅做演示
1、定义表示属性的对象
1 public static readonly DependencyProperty IdProperty;
2、注册附加属性
1 IdProperty = DependencyProperty.RegisterAttached("Id", typeof(int), typeof(ControlExtension));
如果要设置默认值及值验证,可以参考这里,这里暂时不做详细的介绍,后面有时间再补上。
3、添加"属性包装器"
这里和依赖属性的属性包装器不太一样,这里变成了Getxxx和Setxxx函数的形式。
1 public static int GetId(DependencyObject dependencyObject)
2 {
3 return (int)dependencyObject.GetValue(IdProperty);
4 }
5
6 public static void SetId(DependencyObject dependencyObject,int value)
7 {
8 dependencyObject.SetValue(IdProperty, value);
9 }
4、使用附加属性
XAML赋值
1 <Window x:Class="IntroductionToAttachedProperty.MainWindow"2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"6 xmlns:local="clr-namespace:IntroductionToAttachedProperty"7 mc:Ignorable="d"8 Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">9 <Grid Name="grid" local:ControlExtension.Id="100"> 10 11 </Grid> 12 </Window>
在后台代码中获取附加属性的值
1 private void Window_Loaded(object sender, RoutedEventArgs e)
2 {
3 MessageBox.Show(ControlExtension.GetId(this.grid).ToString());
4 }
在后台代码中赋值
1 ControlExtension.SetId(this.grid, 100);
总结
WPF的属性在MVVM模式开发中非常关键,所以有必要了解清楚。本文仅介绍了依赖属性和附加属性的基础概念,对于掌握MVVM模式基础开发来说,已经够用。
本文不包括依赖属性内存存储方式、属性取值优先级、属性默认值、属性值更改回调、属性验证等概念,在后面的文章中再进行补充。
参考资料
https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/properties/dependency-properties-overview?view=netdesktop-8.0&source=recommendations
示例代码
https://github.com/zhaotianff/WPF-MVVM-Beginner/tree/main/2_DependencyProperty
相关文章:
WPF MVVM入门系列教程(二、依赖属性)
说明:本文是介绍WPF中的依赖属性功能,如果对依赖属性已经有了解了,可以浏览后面的文章。 为什么要介绍依赖属性 在WPF的数据绑定中,密不可分的就是依赖属性。而MVVM又是跟数据绑定紧密相连的,所以在学习MVVM之前&…...
Springboot集成syslog+logstash收集日志到ES
Springboot集成sysloglogstash收集日志到ES 1、背景 Logstash 是一个实时数据收集引擎,可收集各类型数据并对其进行分析,过滤和归纳。按照自己条件分析过滤出符合的数据,导入到可视化界面。它可以实现多样化的数据源数据全量或增量传输&…...
Devops业务价值流:软件研发最佳实践
在当今快速迭代的软件开发环境中,DevOps业务价值流已成为推动软件研发高效与质量并重的关键实践。软件研发阶段作为产品生命周期的核心环节,其每一步都承载着将创意转化为现实的重要使命。在历经需求澄清的精准定位、架构设计的宏观规划以及项目初始化的…...
Matplotlib 绘图艺术:从新手到高手的全面指南
引言 在数据科学和机器学习领域,数据可视化是一项至关重要的技能。一个优秀的可视化图表可以直观地展示数据的内在规律,帮助我们更好地理解数据,并做出更明智的决策。而在众多的绘图库中,Matplotlib 是 Python 中最强大、最灵活的…...
[ shell 脚本实战篇 ] 编写恶意程序实现需求(恶意程序A监测特定目录B出现特定文件C执行恶意操作D-windows)
🍬 博主介绍 👨🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...
SQLI LABS | Less-33 GET-Bypass AddSlashes()
关注这个靶场的其它相关笔记:SQLI LABS —— 靶场笔记合集-CSDN博客 0x01:过关流程 输入下面的链接进入靶场(如果你的地址和我不一样,按照你本地的环境来): http://localhost/sqli-labs/Less-33/ "Ad…...
界面控件DevExpress WPF中文教程:Data Grid——卡片视图设置
DevExpress WPF拥有120个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…...
flink 内存配置(一):设置Flink进程内存
flink 内存配置(一):设置Flink进程内存 flink 内存配置(二):设置TaskManager内存 flink 内存配置(三):设置JobManager内存 flink 内存配置(四)…...
贪心算法习题其三【力扣】【算法学习day.20】
前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴&am…...
速盾:高防cdn针对网站的好处有哪些?
高防CDN(Content Delivery Network)是一种网络分发技术,它能够提供可靠的网站高防护服务,有效地解决了网站遭受DDoS攻击、恶意流量等网络安全问题。高防CDN的应用已经变得越来越广泛,对于网站的好处也变得越发明显。 …...
【Java SE语法】抽象类(abstract class)和接口(interface)有什么异同?
目录 1. 抽象类与接口的基本概念 1.1 抽象类 1.2 接口 2. 抽象类与接口的异同 2.1 相同点 2.2 不同点 3. 拓展知识:多态与设计模式 3.1 多态 3.2 设计模式 4. 结论 在软件工程中,设计模式和代码结构的选择对于构建可维护、可扩展的系统至关重要…...
京准同步:GPS北斗卫星授时服务器发展趋势介绍
京准同步:GPS北斗卫星授时服务器发展趋势介绍 京准同步:GPS北斗卫星授时服务器发展趋势介绍 GPS北斗卫星授时服务器的发展趋势紧密围绕着不断提升的时间同步精度、可靠性、安全性,以及适应广泛应用场景的需求展开,以下是卫星授时…...
鸿蒙多线程开发——并发模型对比(Actor与内存共享)
1、概 述 并发是指在同一时间段内,能够处理多个任务的能力。为了提升应用的响应速度与帧率,以及防止耗时任务对主线程的干扰,HarmonyOS系统提供了异步并发和多线程并发两种处理策略。 异步并发:指异步代码在执行到一定程度后会被…...
【计算机网络】章节 知识点总结
一、计算机网络概述 1. 计算机网络向用户提供的两个最重要的功能:连通性、共享 2. 因特网发展的三个阶段: 第一阶段:从单个网络 ARPANET 向互联网发展的过程。1983 年 TCP/IP 协议成为 ARPANET 上的标准协议。第二阶段:建成三级…...
开箱即用!265种windows渗透工具合集--灵兔宝盒
【渗透工具箱】灵兔宝盒-Rabbit_Treasure_Box_V1.0.1 介绍 Rabbit_Treasure_Box_V1.0.1是一款Windows渗透工具箱,集成Dawn Launcher管理,便捷备份更新。内含脚本工具及在线安全工具,覆盖信息收集、漏洞利用、逆向破解、蓝队防御等多领域&am…...
怎么在哔哩哔哩保存完整视频
哔哩哔哩(B站)作为一个集视频分享、弹幕互动于一体的平台,吸引了大量用户。许多人希望能够将自己喜欢的完整视频保存到本地,以便离线观看或分享。直接下载视频的功能并不总是可用,因此,本文将介绍几种在哔哩哔哩上保存完整视频的方…...
CPU算法分析LiteAIServer视频智能分析平台视频智能分析:抖动、过亮与过暗检测技术
随着科技的飞速发展,视频监控系统在各个领域的应用日益广泛。然而,视频质量的好坏直接影响到监控系统的效能,尤其是在复杂多变的光照条件下和高速数据传输中,视频画面常常出现抖动、过亮或过暗等问题,导致监控视频难以…...
fastGPT调用stable diffusion生成图片,本地模型使用ollama
ps:192.168.1.100换成你的ip 一、开器stable diffusion的api访问 Git上copy的项目,在启动web-ui.bat/sh时加上--api的启动参数. /web-ui.bat --api我这里使用的stabble-diffusion-docker构建的默认就开启了 http://192.168.1.100:7860/docs 二…...
【jmeter】jmeter的线程组功能的详细介绍
初衷 之前在公司做的性能测试基本上都是关于数据库的,针对接口的性能测试还是比较少一点。考虑到后边大模型问答产品的推广,公司方面也要求对相关接口进行压测,也趁着这个机会,对jmeter进行深入研究,进一步加强自己性…...
高边坡安全监测系统的工作原理和应用领域
高边坡安全监测系统的工作原理主要依赖于各种先进的传感器设备,这些传感器能够实时地捕捉和记录边坡的位移、应力、裂缝、倾斜和沉降等多种关键数据。这些数据的采集是通过高精度的监测设备进行的,确保了数据的准确性和可靠性。采集到的数据随后通过高效…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
