一句话:山不让尘乃成其高,水不辞盈方有其阔。
摘要:
我将带领大家从零基础入门C#、WPF、数据库,从C#的语法学起,不断深入学习OOP思想(面向对象编程)以及C#高级知识,以实战的方式快速理解封装、继承、多态、抽象、接口、属性、委托、事件、泛型、特性、反射、多线程的概念并掌握其用法,然后,以由浅入深的方式,从整体到细节的渐进学习路径,理论结合实战,学习数据库+WPF框架,包含WPF概述、控件集合、数据绑定、模板样式、资源字典、命令系统、依赖属性、路由事件、动画行为、2D绘图、3D变换等。一条龙专题套餐帮您学透.Net桌面软件开发,成为资深的C#+WPF开发工程师。
详情:
学习分为5个阶段,根据您目前所处的阶段,选择合适的出发点,接下来我将每一个阶段的要求阐述如下:
第一阶段:零基础阶段。
在这一阶段中,您需要了解计算机的组成,操作系统的大致情况,熟练的键盘打字操作、软件的概念,开发环境的安装调试,需要学习C#语言的基础知识,掌握数据类型、常量、变量、运算符、控制流程、判断、循环、封装、方法、数组、字符串、枚举、类型等知识点。如果您在学生时代学过一些计算机基础课程,比如计算机组装与维护、计算机网络基础、操作系统、数据库、office办公系统,英语,那么对于C#的基础语法及运行调试有一定的优势。如果您已具备这些知识,那么可以开展下一个阶段的学习。本阶段可以学习我的《C#编程零基础系列课程》课程。
第二阶段:入门初级阶段
在这一阶段中,您已经具备一定的编程常识,可以根据视频课程的实战引导进行实战学习,对于学习过程中遇到的问题,通过开发环境的Debug错误调试,能修改一些书写语义代码错误,并对一些OOP方面的错误有一定的领悟。所以您需要学习WPF框架的基本语法,通过对class类型的学习,能理解XAML中的控件(本质就是类型)的实例化与使用,能实现简单的界面布局,关于界面布局和控件使用的初级能力可以在我的《WPF框架系列课程(小白进阶选择)》前60集进行学习和实战。C#语言方面,则要求掌握C#的封装、继承、多态、抽象、接口、委托和事件这些概念与用法,可以在《C#编程零基础系列课程(筹备中)》进行学习。为接下来的中级阶段打下良好的基础。
第三阶段:中级阶段。
通过前面两个阶段的学习,除了数据库方面未涉及,基本可以开发一些简单的小程序。要步入中级阶段,我们任然需要从几个方面进行提升,首先是C#语言,本阶段需要掌握C#的高级知识,比如特性、反射、属性、索引器、集合、泛型、匿名方法、拉姆达表达式、多线程,项目折解与引用,只有掌握这些知识,才能迈向高级阶段。在WPF方面,需要学习WPF的MVVM编程模式、模板、样式、命令、资源字典、绑定等高级知识。掌握一种数据库的开发,学习SQL语法,能用运用FrameworkEntity框架对数据库进行删除改查操作。至此,您已具备C#+WPF的桌面软件开发中级水平,为接下来的实战项目打下坚实的开发基础。同时,对于转行或刚毕业的大学生,可以应聘一些C#软件开发的初级岗位,实现程序员之路的第一步。关于这一部分的课程,可以在《WPF框架系列课程(小白进阶选择)》、《C#编程高级系列课程(筹备中)》、《C#+WPF实战超市管理系统》这些课程学习。
第四阶段:高级阶段。
在这一阶段中,我们将把C#、WPF、数据库所学的知识进行整合与灵活运用,能够独立开发项目。C#方面将继续学习一些框架级的内容,深入理解IOC思想(控制反转和依赖注入),从常见的开发框架中去理解C#的高级知识和IOC容器的高级应用,如mvvmlight、prism、CommunityToolkit.Mvvm、ReactiveUI等常见框架,够用借助这类框架帮助自己快速开发软件,而不必重复开发轮子。能够阅读并理解其他人的源代码,并从中发现问题或吸收营养。关于这方面的知识可以在我的《Prism框架的学习课程》、《PLC与串口网口通讯模块开发》、《C#23种设计模式实战课程》、《WPF高级实战课程(知产代理数字化解决方案)》进行学习。
第五阶段:架构师阶段。
在这一阶段中,我们需要通过一些实战来领悟软件架构的概念,并掌握软件架构的能力,在我的《C#+WPF上位机开发课程(模块化与反应式编程)》、《C#+WPF上位机开发反应釜控制系统》课程中,我详细的演示了如何将一个实实在在的事物进行抽象,并利用模块进行业务逻辑实现。这些事物,通常拥有某一些相同类型的逻辑操作,或者相同功能的硬件,它们彼此可以替换,拥有共同的基类或接口。比如上位机软件中我们经常要用到相机,同一类型的相机拥有不同的厂家,假如今年我们用巴斯勒工业相机,明年换成海康相机,后年换成大华相机,为了方便软件开发和升级替换,就可以将相机抽象成一个独立的接口模块(虚),三个不同厂家的相机独立成子模块(实),实际使用时,用哪个相机就加载哪个模块,虚实结合开发,项目源代码便拥有了更好的解耦和扩展能力。
课程列表
1.《C#编程零基础系列课程》(已发布)
2.《C#编程高级系列课程》(筹备中)
3.《WPF框架系列课程(小白进阶选择)》(已发布)
4.《C#+WPF实战超市管理系统》(已发布)
5.《PLC与串口网口通讯模块开发》(已发布)
6.《Prism框架的学习课程》(已发布)
7.《C#+WPF上位机开发反应釜控制系统》(已发布)
8.《C#+WPF上位机开发课程(模块化与反应式编程)》(已发布)
9.《C#23种设计模式实战课程》(已发布)
10.《WPF高级实战课程(知产代理数字化解决方案)》(已发布)
——重庆教主 2023年10月30日
要说到WPF的起源,这事儿还得从一个叫比尔盖茨的人说起。生于1955年10月28日的比尔盖茨,从13岁就开始学习计算机编程与设计。后来在大三的时候,又说服爸妈从哈佛大学辍学,与好友保罗艾伦于1975年4月4日一起创办了微软公司,彼时19岁。最初,微软公司以开发BASIC程序为主营业务。
BASIC语言是什么?
BASIC是一种直译式的编程语言,全称Beginners' All-purpose Symbolic Instruction Code,意思就是“初学者通用符号指令代码”,在完成编写后不须经由编译及连结等手续即可执行,但如果需要单独执行时仍然需要将其建立成执行档。BASIC是由达特茅斯学院院长、匈牙利人约翰·凯梅尼(John G. Kemeny)与数学系教师托马斯·卡茨(Thomas E. Kurtz)共同研制出来的。1964年BASIC语言正式发布。第一个BASIC程序在1964年5月1日早上4时,由BASIC编译程序进行编译后成功运行 。1975年,比尔·盖茨把它移植到PC上。
五年后,IBM公司委托微软为其PC开发操作系统,由于时间紧迫,微软便从西雅图一名叫帕特森手中花了5万美元购买了一款叫QDOS的操作系统,然后对源代码进行了二次开发,并命名为MS-DOS,并在上世纪80年代成为了标准的操作系统。
1985年,微软开始将MS-DOS操作系统图形化,Windows1.0初具雏形,并于1995年正式发布了著名的Windows95图形操作系统。随后就是Windows98和如今风靡全球的Windows XP、Windows 7、Windows 8、Windows 10及最近发布的Windows 11。
在如此多的操作系统版本上开发和运行应用程序,其兼容性的问题一直困扰着程序员。程序员面临着众多不同的开发语言和编程平台,为了解决这个问题,2002年.Net Framework框架横空出世。
那么.Net Framework框架是干嘛的?一句话,提供了一个统一的开发环境和基础设施,使程序员能够更容易的构建和部署应用程序。它包括了一个称为公共语言运行时(Common Language Runtime,简称CLR)的虚拟机,以及.NET类库(Framework Class Library,简称FCL),其中包含了大量的可重用的代码和功能。CLR提供了一种管理应用程序的执行环境,包括内存管理、安全性、异常处理和线程管理等。
最初的.Net Frameworks框架只能运行在Windows操作系统之上,那么基于.Net Framework框架开发和部署的应用程序也只能运行在Windows操作系统上面,因为孩子总得随父母跑嘛。但是这个世界上除了Windows操作系统之外,还有Unix、Linux、macOS、ChromeOS等操作系统,可谓半壁江山弃之可惜,于是微软在2016年发布了.NET Core,它具有更小、更快、更模块化的特点,并且支持用于构建云原生应用的微服务架构。
在2020年,微软宣布.NET Core将与.NET Framework合并为一个新的版本,即.NET 5。这个版本统一了.NET的生态系统,旨在提供一个全面的、跨平台的.NET开发体验。此后,微软持续发布新的.NET版本,如.NET 6、.NET 7等,以不断改进和增强框架的功能和性能。
在.NET Framework3.0时(2006年9月1日),微软推出了WPF(Windows Presentation Foundation),翻译成中文叫窗体呈现基础。因为在此之前,程序员在开发桌面应用程序时,所采用的UI框架是WinForm。从开发者的直观感受而言,WinForm框架采用鼠标拖拽控件的方式进行界面布局,而WPF虽然支持鼠标拖拽,但更推荐的编码方式是通过键盘编写类似XML标签语言进行界面布局。
简单介绍一下WinForm框架,WinForm是.Net平台对Windows Form的简称。以 .NET Framework 为基础,微软公司在WinForm框架中为我们提供了丰富的控件,大多数控件都派生于 System.Windows.Forms.Control类。利用Windows窗体和可视化控件,可以创建丰富的基于Windows的应用程序。其界面元素的绘制则是通过GDI+来实现的。GDI+是微软公司推出的一种图形设备接口,它提供了一系列的绘图函数和类,可以用于创建和操作图形图像、字体和颜色等。在WinForm中,开发人员可以使用GDI+提供的函数和类来创建和绘制各种界面元素,例如按钮、文本框、标签等。
虽然WinForm有如此多的优化,但是长江后浪推前浪,自古新人胜旧人。现如今,越来越多的公司在开发新项目时,往往都采用WPF前端框架,这一切的根源是为什么呢?我们请出WinForm和WPF两位选手进行一场面对面的PK。
一、交互方式
WinForm提供了一种基于事件驱动的编程模型,开发者可以通过在控件上注册事件处理程序来响应用户交互。而WPF采用前后端代码分离的方式编码,前端采用XAML(可扩展应用程序标记语言)来定义用户界面,后端采用VB、C#等编程语言,那么当前后端代码分离后,前端控件的交互如何传递给后端呢?答案是通过命令绑定(Command Binding)和数据绑定(Data Binding)的方式。这样做的好处是让前端设计师专注于界面设计,后端开发人员专注于业务逻辑开发,二者互相配合,齐头并进。 故WPF是一种基于数据驱动的编程模型。
XAML语言是什么 ?
XAML和XML语义结构类似,而XML的前身是标准通用标记语言,是自IBM从60年代就开始发展的通用标记语言。同HTML一样, 可扩展标记语言是标准通用标记语言的一个 子集,它是描述网络上的数据内容和结构的标准。
二、界面布局
WinForm使用基于像素的布局模型,开发者需要手动指定控件的位置和大小。这种方式对于简单的界面设计来说是足够的,但在处理复杂的布局时可能变得繁琐。而WPF使用基于向量的布局模型,通过使用面板(Panel)和布局容器(Layout Container)等元素来自动调整控件的位置和大小。这种灵活的布局模型使得开发者可以更方便地创建复杂和可扩展的界面。
三、模板样式
WinForm窗体和控件的美化是一项十分繁琐的工程,往往需要借助第三方控件库或开发者自行绘制更高级的视觉呈现效果;而WPF提供了丰富的模板样式,引入了3D图形和动画等高级特性,可以轻松地开发出生动友好的用户界面。
四、开发模式
在WinForm中,开发者通常需要手动编写代码来实现数据的更新和同步,这可能会导致代码的重复和冗余。例如前端控件的某个内容值需要更改,往往需要在后台直接去修改这个控件的属性值,虽然WinForm也提供了数据绑定,那也只是数据源和控件属性值的基础绑定;
在WPF中,开发者可以通过简单的声明式语法,将界面控件与后台数据模型进行绑定,实现数据的双向传递。此外,WPF还提供了Command绑定机制,允许将界面上的操作与后台命令逻辑进行关联。这种MVVM模式的应用使得开发者可以更好地组织和管理代码,提高开发效率。
五、性能对比
在性能方面,WinForm通常比WPF更加高效。由于其较低的资源消耗和简单的界面模型,WinForm应用程序在运行时通常具有更快的响应速度和较低的内存占用。此外,由于WinForm是自包含的,开发者可以将应用程序作为单个可执行文件部署,无需依赖其他框架。
相比之下,WPF应用程序的性能通常较低。WPF使用了更复杂的图形渲染引擎,并提供了更多的图形特性,这导致它在某些情况下可能会比WinForm消耗更多的系统资源。此外,WPF应用程序还需要依赖.NET Framework和其他相关组件,因此在部署时可能需要额外的安装和配置步骤。
通过上述5场PK,对于二者的区别,相信各位已然是了然于心,随着现代计算机硬件性能的不断加持,性能已经不再是WPF的短板了。
这里引述了微软官方对于WPF的阐述。
WPF的核心是一个与分辨率无关且基于矢量的呈现引擎,旨在充分利用现代图形硬件。 WPF 通过一套完善的应用程序开发功能对该核心进行了扩展,这些功能包括可扩展应用程序标记语言 (XAML)、控件、数据绑定、布局、二维和三维图形、动画、样式、模板、文档、媒体、文本和版式。 WPF 属于 .NET,因此可以生成整合 .NET API 其他元素的应用程序。
这就是WPF!
——重庆教主 2023年8月5日
WPF,全称Windows Presentation Foundation,中文叫Windows呈现基础,WPF也被调侃为“我佩服”。
熟悉XML或HTML网页的小伙伴们,对WPF会感觉到非常的熟悉和亲切。因为它用起来,与开发Web网页前端界面实在没什么两样。
HTML是什么?
超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。它定义了网页内容的含义和结构。HTML 元素通过“标签”(tag)将文本从文档中引出,标签由在“<”和“>”中包裹的元素名组成,HTML 标签里的元素名不区分大小写。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>这里是网页的标题,它显示在浏览器的标题栏里</title>
</head>
<body>
<h1>我的第一个标题</h1>
<p>我的第一个段落。</p>
</body>
</html>
如上述源码所示,<html>和</html>是一对标签,代表其中被“包括”起来的内容为网页源代码,<head>和</head>也是一对标签 ,代表这张网页的头部,您可以在其中定义一些基础数据,例如网页的编码格式,网页的标题等;<body>与</body>代表网页的“身体”,即展示在浏览器里面供用户阅读的内容。它们通常包含文字、图片、视频等内容。
那么以XMAL语言编写的WPF前端代码是什么样子的呢?
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="窗体标题"
Width="250" Height="100">
<!-- 灰色内容表示注释内容 -->
<Button Name="button">按钮文字</Button>
</Window>
我们对比两份源码,除了关键词不同,在代码的格式和语义结构表述上,基本是一模一样的。我们这一节分享的是WPF的概述内容,故上述源码的具体含义将不在这里阐述。我们要探讨的是WPF是什么,由哪些组件构成,WPF能干什么。
一、WPF是什么
没错,它本质上是一个类库,为我们提供了构建Windows桌面应用程序所需的各式各样的类型(class)。当然一个类库还不能称之为框架,实际上,它的长相是这样的:
二、WPF的构成
如图所示,WPF被分成上中下三层,处于最底层的Direct3D和User32其实跟WPF一点关系都没有,我们可以把两个组件视为Windows操作系统的一部分。
1995年2月微软买下RenderMorphics公司,于是该公司的创始人Servan Keondjian便顺理成章的成为了微软的人,从Windows95开始主持开发3D图形引擎(Direct3D)。WPF的3D渲染便是基于Direct3D组件的计算;我们再看User32,这是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息。
中间层分别是milcore.dll和Windowcodecs.dll两个类库,其实两个类库本质上也不属于WPF框架,因为它们是属于非托管层的本地类库,也就是说还没进入到.Net Framework体系中。milcore.dll是一个叫图形托管的引擎,它是WPF的渲染核心,包含最主要的媒体集成层 Media Integration Layer (MIL) 的基础支持,作用是封装 Dx 的接口支持 2D 和 3D 的渲染;Windowcodecs.dll主要是对图片的支持,例如WPF对图片的旋转和缩放。
好,最后介绍一下最上层的三个组件,分别是PresentationFramework.dll、PresentationCore.dll和WindowsBase.dll。我们要开发过程中所使用的绝大多数类型(class)都包含在这三个类库中。
首先说一下WindowsBase.dll,它是上层中最基础的类库,如WPF框架的基类DispatcherObject和DependencyObject。需要说明的是:DependencyObject继承于DispatcherObject抽象类。
再看PresentationCore.dll,提供WPF较低层的一些功能。例如Visual和UIElement这两个类都被包含在这个dll库中,UIElement作为Visual的子类,Visual作为DependencyObject,DependencyObject作为DispatcherObject最终抽象基类。Visual主要提供了几何(Geometry)、特效(Effect)、缩放平移旋转(Transform)等功能;UIElement主要提供了一些基础路由事件(RoutedEvent)、以及定义了一些控件的显示、显示裁剪、是否具有焦点、是否启用等属性。
最后是PresentationFramework.dll,它离我们最近,WPF所有绘制在界面上的控件,全部来源于此类库,包括应用程序的窗口、页面、和用于布局的Panel ,各种控件(Control)和 Style样式, 此外还有交互的控制与动画。在这个dll库中,所有的控件都继承于FrameworkElement类,FrameworkElement类则继承于PresentationCore.dll的UIElement类。
于是我们将上述三层中所引用到的dll库合并起来,最终形成了WPF框架。WPF框架一部分引用了操作系统的本地类库,一部分属于它自身的类库,这些自身类库“运行”在.Net Framework框架之上。
三、WPF能干什么
WPF是一个UI(Uesr Interface 用户界面)框架,本质上就像画家的纸笔,我们可以利用微软为我们写好的各种类,在开发应用程序时,设计出更友好的界面,为用户提供更优质的软件使用体验。所以,WPF从控件的角度出发,我认为可分为三种,第一是布局类的控件,第二是数据内容控件,第三是图形;而为了更美观的界面效果,WPF提供了模板、样式、触发器、资源等内容,允许程序员像使用css一样去定义同一类型或单个控件的外观样式。
WPF框架还引入了全新的MVVM开发模式,旨在帮助程序员更方便的开发软件。以数据驱动的方式替代过去的事件驱动方式,能过引入绑定的概念,将前后端的代码进行分离,不得不说,这是WPF最赋有革命性的创举。
WPF还能干什么?
WPF提供了一组灵活的图形功能。其图形的缩放与电脑硬件和分辨率无关,意味着它在放大时将不会像jpg图片一样显示模糊,倒是像Png矢量图一样,每个像素都会自动缩放。WPF的坐标系统是双精度型(double) ,意味着控件的转换和不透明度的计算精度更高;WPF还充分利用GPU进行动画渲染绘制,尽量减少CPU的负担。
WPF对图像、音频、视频、文字和版式的支持都十分友好。例如MediaElement 控件能够播放视频和音频,并且其足够灵活,可以用作其他自定义媒体播放器的基础。
——重庆教主 2023年8月7日
许多小伙伴如果没有接触过Web开发,特别是对React、Vue等前端框架没有开发经验,习惯了WinForm的拖拽布局方式,在首次接触WPF时,一时间会感觉有些扑朔迷离、力不从心。笔者以前也是从WinForm转过来的,对于WPF的数据绑定、触发器、模板、样式、命令、依赖属性、路由事件等概念和实际应用,也曾走过不少弯路。鉴于此,我希望借助自己搭建的WPF中文网平台,将过去踩过的坑、形成的经验分享出来,以资后来人。
WPF作为一款桌面程序的UI框架,其实在计算机软件领域中,算是很小很小的一个知识分支,通常学校是不会排课的,所以对于大部分程序员而言,WPF框架都是自学的。那么要怎么样学呢?
学习前提
首先,如果将来以C#+WPF开发桌面应用程序,那么C#的基础知识和高级知识是必须掌握的。通常我们对于C#初学者而言,可能刚好掌握了C#的基础知识,例如C#的常量、变量、控制流程、函数、类型,也了解C#的抽象、继承、多态、封装、委托、事件、回调函数等,熟悉WinForm控件的常规使用,这些知识在学习和开发简单的WinForm应用程序可能足够写出一些Demo,但是,一旦开始学习WPF,不但前端XAML要手动编写,而且在XAML的写法中,又要理解绑定、触发器、模板、样式、命令这些类型的作用,以及它们在前后端的实例化和业务上的相互关系,属实有些蒙圈。所以接下来就学习前提简要分析一下。
public int Width
{
get { return (int)GetValue(WidthProperty); }
set { SetValue(WidthProperty, value); }
}
// Using a DependencyProperty as the backing store for Width. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WidthProperty =
DependencyProperty.Register("Width", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
就拿上面的代码举例,我们定义了一个WPF的依赖属性WidProperty,然后通过属性包装器以普通属性Width对外暴露。真正定义依赖属性的关键词是DependencyProperty,以及它的静态方法Register,从Register所需要参数来看,第二个参数和第三个参数要求传入两个反射对象实例,可见WPF在这里使用了C#反射技术。
另外,再看一个微软官方提供的关于路由事件的自定义代码。
// Register a custom routed event using the Bubble routing strategy.
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
name: "Tap",
routingStrategy: RoutingStrategy.Bubble,
handlerType: typeof(RoutedEventHandler),
ownerType: typeof(CustomButton));
// Provide CLR accessors for adding and removing an event handler.
public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}
观察上面的代码,不难看出,RouteEvent代表一个路由事件,并使用EventManager.RegisterRoutedEvent方法成员向WPF事件系统注册了一个叫Tap的事件,这里不单使用了反射,还使用了C#的事件(event)关键词。而要掌握event关键词的概念及用法,委托知识也是必须要理解透彻的。所以要想学会WPF框架,下面这些关于C#语言的编程知识是必须掌握的。
- 熟悉OOP面向对象编程思维,掌握抽象、继承、多态、封装的概念和应用;
- 掌握C#的基本语法、数据类型、程序结构、类型定义、方法成员、常量、变量、数组等基础知识;
- 掌握C#的特性(Attribute)、 反射(Reflection)、 属性(Property)、 索引器(Indexer);
- 掌握C#的委托(Delegate)、 事件(Event)、 集合(Collection)、 泛型(Generic);
- 了解XML或HTML语义结构;
学习路线
要论学习路线,无外呼两种,一是先学整体知识框架,再逐一学习各项细节知识;二是反过来,先从细节入手,一点一滴的啃,最终学完所有细节,从而形成对整体知识框架的认知。在这里我推荐第一种方法,所以我将WPF的学习路线安排如下:
最后建议
山不让尘乃成其高,水不辞盈方有其阔。学习WPF并坚持学习WPF,很快您将从WPF小白蜕变成WPF大佬,加油!
——重庆教主 2023年8月8日