当前位置: 首页 > news >正文

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的属性包装器),但是没有私有变量,而是通过GetValueSetValue来完成取值和赋值。

依赖属性在使用上依赖属性和.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、添加"属性包装器"

这里和依赖属性的属性包装器不太一样,这里变成了GetxxxSetxxx函数的形式。

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入门系列教程(二、依赖属性)

说明&#xff1a;本文是介绍WPF中的依赖属性功能&#xff0c;如果对依赖属性已经有了解了&#xff0c;可以浏览后面的文章。 为什么要介绍依赖属性 在WPF的数据绑定中&#xff0c;密不可分的就是依赖属性。而MVVM又是跟数据绑定紧密相连的&#xff0c;所以在学习MVVM之前&…...

Springboot集成syslog+logstash收集日志到ES

Springboot集成sysloglogstash收集日志到ES 1、背景 Logstash 是一个实时数据收集引擎&#xff0c;可收集各类型数据并对其进行分析&#xff0c;过滤和归纳。按照自己条件分析过滤出符合的数据&#xff0c;导入到可视化界面。它可以实现多样化的数据源数据全量或增量传输&…...

Devops业务价值流:软件研发最佳实践

在当今快速迭代的软件开发环境中&#xff0c;DevOps业务价值流已成为推动软件研发高效与质量并重的关键实践。软件研发阶段作为产品生命周期的核心环节&#xff0c;其每一步都承载着将创意转化为现实的重要使命。在历经需求澄清的精准定位、架构设计的宏观规划以及项目初始化的…...

Matplotlib 绘图艺术:从新手到高手的全面指南

引言 在数据科学和机器学习领域&#xff0c;数据可视化是一项至关重要的技能。一个优秀的可视化图表可以直观地展示数据的内在规律&#xff0c;帮助我们更好地理解数据&#xff0c;并做出更明智的决策。而在众多的绘图库中&#xff0c;Matplotlib 是 Python 中最强大、最灵活的…...

[ shell 脚本实战篇 ] 编写恶意程序实现需求(恶意程序A监测特定目录B出现特定文件C执行恶意操作D-windows)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

SQLI LABS | Less-33 GET-Bypass AddSlashes()

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-33/ "Ad…...

界面控件DevExpress WPF中文教程:Data Grid——卡片视图设置

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…...

flink 内存配置(一):设置Flink进程内存

flink 内存配置&#xff08;一&#xff09;&#xff1a;设置Flink进程内存 flink 内存配置&#xff08;二&#xff09;&#xff1a;设置TaskManager内存 flink 内存配置&#xff08;三&#xff09;&#xff1a;设置JobManager内存 flink 内存配置&#xff08;四&#xff09;…...

贪心算法习题其三【力扣】【算法学习day.20】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…...

速盾:高防cdn针对网站的好处有哪些?

高防CDN&#xff08;Content Delivery Network&#xff09;是一种网络分发技术&#xff0c;它能够提供可靠的网站高防护服务&#xff0c;有效地解决了网站遭受DDoS攻击、恶意流量等网络安全问题。高防CDN的应用已经变得越来越广泛&#xff0c;对于网站的好处也变得越发明显。 …...

【Java SE语法】抽象类(abstract class)和接口(interface)有什么异同?

目录 1. 抽象类与接口的基本概念 1.1 抽象类 1.2 接口 2. 抽象类与接口的异同 2.1 相同点 2.2 不同点 3. 拓展知识&#xff1a;多态与设计模式 3.1 多态 3.2 设计模式 4. 结论 在软件工程中&#xff0c;设计模式和代码结构的选择对于构建可维护、可扩展的系统至关重要…...

京准同步:GPS北斗卫星授时服务器发展趋势介绍

京准同步&#xff1a;GPS北斗卫星授时服务器发展趋势介绍 京准同步&#xff1a;GPS北斗卫星授时服务器发展趋势介绍 GPS北斗卫星授时服务器的发展趋势紧密围绕着不断提升的时间同步精度、可靠性、安全性&#xff0c;以及适应广泛应用场景的需求展开&#xff0c;以下是卫星授时…...

鸿蒙多线程开发——并发模型对比(Actor与内存共享)

1、概 述 并发是指在同一时间段内&#xff0c;能够处理多个任务的能力。为了提升应用的响应速度与帧率&#xff0c;以及防止耗时任务对主线程的干扰&#xff0c;HarmonyOS系统提供了异步并发和多线程并发两种处理策略。 异步并发&#xff1a;指异步代码在执行到一定程度后会被…...

【计算机网络】章节 知识点总结

一、计算机网络概述 1. 计算机网络向用户提供的两个最重要的功能&#xff1a;连通性、共享 2. 因特网发展的三个阶段&#xff1a; 第一阶段&#xff1a;从单个网络 ARPANET 向互联网发展的过程。1983 年 TCP/IP 协议成为 ARPANET 上的标准协议。第二阶段&#xff1a;建成三级…...

开箱即用!265种windows渗透工具合集--灵兔宝盒

【渗透工具箱】灵兔宝盒-Rabbit_Treasure_Box_V1.0.1 介绍 Rabbit_Treasure_Box_V1.0.1是一款Windows渗透工具箱&#xff0c;集成Dawn Launcher管理&#xff0c;便捷备份更新。内含脚本工具及在线安全工具&#xff0c;覆盖信息收集、漏洞利用、逆向破解、蓝队防御等多领域&am…...

怎么在哔哩哔哩保存完整视频

哔哩哔哩(B站)作为一个集视频分享、弹幕互动于一体的平台&#xff0c;吸引了大量用户。许多人希望能够将自己喜欢的完整视频保存到本地&#xff0c;以便离线观看或分享。直接下载视频的功能并不总是可用&#xff0c;因此&#xff0c;本文将介绍几种在哔哩哔哩上保存完整视频的方…...

CPU算法分析LiteAIServer视频智能分析平台视频智能分析:抖动、过亮与过暗检测技术

随着科技的飞速发展&#xff0c;视频监控系统在各个领域的应用日益广泛。然而&#xff0c;视频质量的好坏直接影响到监控系统的效能&#xff0c;尤其是在复杂多变的光照条件下和高速数据传输中&#xff0c;视频画面常常出现抖动、过亮或过暗等问题&#xff0c;导致监控视频难以…...

fastGPT调用stable diffusion生成图片,本地模型使用ollama

ps&#xff1a;192.168.1.100换成你的ip 一、开器stable diffusion的api访问 Git上copy的项目&#xff0c;在启动web-ui.bat/sh时加上--api的启动参数. /web-ui.bat --api我这里使用的stabble-diffusion-docker构建的默认就开启了 ​ ​ http://192.168.1.100:7860/docs 二…...

【jmeter】jmeter的线程组功能的详细介绍

初衷 之前在公司做的性能测试基本上都是关于数据库的&#xff0c;针对接口的性能测试还是比较少一点。考虑到后边大模型问答产品的推广&#xff0c;公司方面也要求对相关接口进行压测&#xff0c;也趁着这个机会&#xff0c;对jmeter进行深入研究&#xff0c;进一步加强自己性…...

高边坡安全监测系统的工作原理和应用领域

高边坡安全监测系统的工作原理主要依赖于各种先进的传感器设备&#xff0c;这些传感器能够实时地捕捉和记录边坡的位移、应力、裂缝、倾斜和沉降等多种关键数据。这些数据的采集是通过高精度的监测设备进行的&#xff0c;确保了数据的准确性和可靠性。采集到的数据随后通过高效…...

Java:多态的调用

1.什么是多态 允许不同类的对象对同一消息做不同的响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。&#xff08;发送消息就是函数调用&#xff09;。多态使用了一种动态绑定&#xff08;dynamic binding&#xff09;技术&#xff0c;指在执行期间判断所引用…...

A day a tweet(seventeen)——Visualize Convolution Neural Network!

a.形象化地CNNs visually explained! . .CNN(Convolution Neural Network) 卷积神经网络 a.不可思议的,难以置信的 v.使形象化CNN explainer is an incredible interactive tool to visualize the internal workings of a CNN. n.解释器;讲解员 …...

卡达掐发展史

自行车是一种简单而又伟大的交通工具。自从19世纪诞生以来&#xff0c;它不仅改变了人们的出行方式&#xff0c;也深刻地影响了我们的生活方式、城市布局以及健康观念。作为一种绿色、经济的出行工具&#xff0c;自行车至今仍在全球范围内被广泛使用。本文将从自行车的历史、结…...

UI界面设计入门:打造卓越用户体验

互联网的迅猛发展催生了众多相关职业&#xff0c;其中UI界面设计师成为互联网行业的关键角色之一。UI界面设计无处不在&#xff0c;影响着网站、应用程序以及其他数字平台上的按钮、菜单布局、色彩搭配和字体排版等。UI设计不仅仅是字体、色彩和导航栏的组合&#xff0c;它的意…...

【Linux:tcp三次握手和四次挥手】

目录 三次握手&#xff1a; 两次握手 丢包问题与乱序问题 四次挥手 为什么客户端需要等待超时时间&#xff1f; TCP报文中含有SYN、ACK、FIN等标识&#xff0c;把这些标识设置1就是开启这些标识&#xff0c;设置为0就是关掉这些标识 三次握手&#xff1a; 在客户端发送tc…...

大数据Informatica面试题及参考答案

目录 什么是 Informatica?它主要解决什么问题? 什么是 Informatica PowerCenter? Informatica PowerCenter 的主要组成部分有哪些? 解释 Informatica PowerCenter 的主要组件。 Informatica PowerCenter 与 DataStage 有何区别? 解释 Informatica 中的源 (Source) 和…...

Gradient Boosting Regressor(GBDT)--- 论文实战

一、前言 在《机器学习论文复现实战---linear regression》中通过Pearson 相关性分析,去除了2个高相关性特征 "PN" 和 "AN" ,数据维度变为890*25。(数据集地址) 这里我们不做任何前期处理,直接就将数据放入 GBDT 模型中进行训练了。 二、模型训练过程…...

Python教程:python枚举类定义和使用

在Python中&#xff0c;枚举类&#xff08;Enum&#xff09;用于表示一组常量&#xff0c;使代码更加清晰和易于维护。枚举类通过enum模块定义。以下是如何定义和使用枚举类的详细步骤。 定义枚举类 首先&#xff0c;你需要导入enum模块&#xff0c;然后定义一个枚举类。枚举…...

Java学习Day60:微服务总结!(有经处无火,无火处无经)

1、技术版本 jdk&#xff1a;17及以上 -如果JDK8 springboot&#xff1a;3.1及其以上 -版本2.x springFramWork&#xff1a;6.0及其以上 -版本5.x springCloud&#xff1a;2022.0.5 -版本格林威治或者休斯顿 2、模拟springcloud 父模块指定父pom <parent><…...

MySQL日期类型选择建议

我们平时开发中不可避免的就是要存储时间&#xff0c;比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间、用户下单时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的&#xff0c;用的好与不好会给我们的业务甚至功能带来很大的影响。所以…...