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进行深入研究,进一步加强自己性…...
高边坡安全监测系统的工作原理和应用领域
高边坡安全监测系统的工作原理主要依赖于各种先进的传感器设备,这些传感器能够实时地捕捉和记录边坡的位移、应力、裂缝、倾斜和沉降等多种关键数据。这些数据的采集是通过高精度的监测设备进行的,确保了数据的准确性和可靠性。采集到的数据随后通过高效…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
