WPF学习笔记(一)

引言

在桌面开发领域,虽然在某些领域,基于electron的跨平台方案能够为我们带来某些便利,但是由于WPF技术能够更好的运用Direct3D带来的性能提升、以及海量Windows操作系统和硬件资源的支持,所以他依然有着得天独厚的优势。

当然,选用一门技术,依然看公司的基因土壤和综合因素或者老板的心血来潮,例如QT也同样是一门非常不错的跨平台图形界面解决方案。

目前我们公司在桌面开发领域广泛应用了WPF技术,主要是使用其作为大屏数据可视化相关的UI呈现,包括一些数据展示效果、动画效果等。由于之前我对WPF仅有三周经验,因此在开发和设计相关功能时,一些简单功能还能勉强完成,稍微复杂一点的就有点费时过长了,因此这篇文章主要梳理自己的学习笔记,以便总结学习成果。

如何学习WPF技术?

在Quote上有人提出了这样一个相同的问题,查看问题,开发者Srikanth Pagadala如是回答:

1、以了解基础控件作为学习的起步过程:这些控件包括TextBox,Button,TextBlock及其他的,理解这些控件对外提供的属性,以及如何使用。
2、了解和使用布局空间:例如Grid、StackPanel、DockerPanel和其他控件,在这一点上,你需要花费大量的时间。同时你需要学会创建复杂的UI设计。
3、了解循环类型的空间,例如ItemControl控件。
4、了解关于模板的概念。包括如何定义包含CheckBox的Combox,同时这个控件还包含了一张图片的按钮,以及如何在ItemsControl中使用不同的模板。
5、理解数据绑定的运行机制。尝试创建一个MVVM或类似类型的应用程序。
6、创建一个典型的控件,探索DependencyProperties(依赖属性)和AttachedProperties(附加属性)。
7、创建一个样式资源,理解如何给控件设计样式。

除此之外,还有其他开发者给出了补充回答:

1、学习控件的数据绑定过程,在DataGrid上实现数据绑定。
2、学习和实现INotifyPropertyChanged类。查看如何实现
3、学习Observable Collection。该类型的集合广泛使用于数据集合绑定方面,同时也提供了数据改变通知的机制。
4、使网格上的列可编辑。用文本控件(用户项目模板)替换列。为每个捕获文本更改事件的列创建一个属性。在文本控件上使用绑定类型。尝试捕获您在后端在网格上所做的更改。
5、成功将数据控件中的文本控件与后端属性绑定后,请在同一页面上创建网格的副本。尝试同步这两个网格。例如,您在第一个网格中所做的每个更改都必须在第二个网格中自动更新。

网站“https://www.wpf-tutorial.com/”是一个专门用于学习WPF的网站,通过这个网站,可以快速的入门WPF。

由于WPF技术已经比较熟悉,所以书籍也比较多,网友推荐来自刘铁猛老师的《深入浅出WPF》这本书,而我通过Kindle则看到了一本比较有意思的书《葵花宝典-WPF自学手册》,这本书写得比较生动,通过故事的形式讲了WPF的许多技术原理,无形中让我对WPF的概念有了许多新的认识。当然,这本书已经有点年头了。

WPF的常用控件

控件类型 控件名称 控件说明 链接地址
组件 Window 窗口 查看示例
Page 页面 查看示例
NavigationWindow 导航窗口 查看示例
Frame 查看示例
常规控件 Button 按钮控件,提供Content作为内容 查看示例
TextBox 文本框控件,用以输入文本 查看示例
TextBlock 文本块,用以显示文本 查看示例
Label 标签,用以显示文本 查看示例
ProgressBar 进度条 查看示例
ToggleButton 一种可以设置开关三态的按钮 查看示例
Image 图像控件,通过Source设置资源路径 查看示例
CheckBox 勾选框,可以设置是否勾选的三种状态 查看示例
RichTextBox 富文本框,可以多种格式显示和输入文本 查看示例
TreeView 树视图,以树状图的形式显示绑定内容,可以显示是否勾选三态。 查看示例
WebBrowser 浏览器,基于IE内核的浏览器控件 查看示例
Calendar 日历控件 查看示例
ComboBox 下拉列表 查看示例
ContentControl 内容控件 查看示例
Expander 扩展器,可以显示和折叠面板内的元素 查看示例
GroupBox 分组框 查看示例
StatusBar 状态栏,用于在页面下方显示状态信息。 查看示例
DateTimePicker 时间控件,可以设置时间状态。 查看示例
DocumentViewer 文档查看器 查看示例
RadioButton 单选按钮 查看示例
ScollViewer 滚动视图 查看示例
ScollBar 滚动条 查看示例
Separator 分隔器 查看示例
ToolBar 工具条 查看示例
Slider 查看示例
Menu 菜单 查看示例
MediaElement 多媒体控件 查看示例
PasswordBox 密码输入框 查看示例
TabControl 选项卡 查看示例
ToolBarTray 工具条 查看示例
WindowsFormsHost 用以承载WinForm 查看示例
Border 边框 查看示例
数据控件 ListView 列表视图 查看示例
DataGrid 数据表 查看示例
ListBox 列表框 查看示例
布局 WrapPanel 可变面板 查看示例
StackPanel 固定面板 查看示例
DockerPanel 停靠面板 查看示例
Grid 表格布局 查看示例
UniformGrid 统一分布表格布局 查看示例
查看示例 Canvas 画布 查看示例
图形 Point 查看示例
Line 线 查看示例
Path 路径 查看示例
Polygon 多边形 查看示例
Polyline 多段线 查看示例
Rectangle 矩形 查看示例
Shape 画笔 查看示例
Rectangle 矩形 查看示例
Ellipse 椭圆 查看示例

WPF的XAML语法

概述

在WPF技术中引入的XAML语法算是该技术的一大特色,也是被学习者视同为学习路径陡峭的“罪魁祸首”。原因是在前端技术飞速发展的今天,HTML的语法体系由于更早的被开发者接受,所以也自然而然更容易成为开发者的首选。

而XAML是一种脱胎于XML,并吸收了HTML的精华的语法体系,是一种界面描述语言,XML语法本身相对而言较为臃肿的体系,看似成为了他的历史负担,但是其实倒也没那么复杂,通过几个简单的示例,其实就足够掌握这门新的语法体系了。例如,使用这样的语法,完全可以平滑过渡到这样的语法体系。(部分标签其实只是大小写不同)。当然,在XAML中熟练编写样式,确实需要花一点点时间。

在WPF中,通过XAML定义面向用户交互层的界面,然后编译成baml运行,后端则使用C#或VB.NET这样的CLR语法来实现逻辑交互。

XAML的语法定义

XAML的根元素定义

根元素定义是定义XAML的命名空间。


XAML的属性语法

通过xaml定义按钮,并设置文本为 helloworld 。这种写法在官方文档中称为“属性语法”,即直接在XAML中对属性进行设置。

XAML的属性元素语法

通过xaml定义按钮,并设置其背景为蓝色画笔,字体颜色为红色画笔,内容 为helloworld。这种写法在官方文档中称为“属性元素语法”。


XAML的集合语法

定义按钮的颜色为红色和蓝色渐变色,内容为helloworld。这种称为“集合语法”。


  
    
    
    
  

XAML的样式定义

通过属性语法来定义按钮的外观

样式定义使用 标签,然后在中间对样式的内容进行定义。

例如,以下表示通过XAML语法对 ToggleButton 按钮定义了一个命名为 ToggleLikeButtonStyle 的样式。

 

WPF中的模板Template

WPF中的控件可以通过模板 Template 的形式来定义其内容,使得开发者能够通过 XAML 灵活的对控件的外观进行扩展。例如,如下定义了一个 Template,这个控件模板将会对控件(Button)定义填充制定颜色。

   
                  
                      
                          
                              
                                  
                                      
                                  
                              
                              
                          
                      
                  
              

XAML中的触发器Triggers

传统的WinForm开发者习惯于通过事件的机制对按钮的外观进行定义,而在WPF中,则可以通过属性的形式对外观进行设置,这使得开发者更能够写出高质量的代码。

例如,如下代码通过定义触发器,设置控件(控件为 ToggleButton),当控件的勾选状态属性为“IsChecked” 时,其边框填充色为#4696F2颜色。

  
                              
  
                                        
                                            
                                        
                                    
                                
                                
                                
                                
                                
                            
                         
                                    

部分完整代码

在上述事例中,共定义了两个按钮的样式,分别是:

  • FlatButtonStyle,这是个圆角按钮。

  • ToggleLikeButtonStyle,这是一个点赞按钮。

XAML的标记扩展

通过了解WPF的常用控件,我们可以知道自己需要使用的控件有哪些属性,并能使用 XAML 语法对相应的属性进行设置,这种设置方法有别于通过C#代码的形式进行定义的方法,在 XAML中的属性称为 “标记”。标记使用 “{}” 花括号,编译器通过该花括号将语法和XAML语法进行区分。

例如:

 HeaderTemplate="{DynamicResource StretchedHeaderTemplate}"  

标记值的转换与TypeConverters

在进行标记值转换时,有时候需要使用TypeConverters实现类型转换。例如,在上述示例代码中,可以看到使用了字符串“#525252”来定义颜色,在内部就是实现了从字符串到 Color 类的转换过程。限于篇幅有限,此处就暂时略过。

XAML中内置特殊标记扩展

  • x:Type:特定类型
    
 
 
  • x:Static:使用静态值。
    
 
 
  • x:Null:使用空对象定义为属性值。
    
 
 
  • x:Array:使用数组对象。
    
  arrayContents    
    

常见的标记扩展

  1. StaticResource:通过替换已定义资源的值来为属性提供内容,该资源标记在XAML加载时自动执行。静态资源无法通过在XAML语法体系中对其引用关系进行前向引用,意味着无法通过多层级关系定义可复用的样式资源,如果需要这样做,则需要使用DynamicResource。
    
 
 
  1. DynamicResource:在运行时为资源提供内容。
    
 
 
  1. Binding:在运行时为使用数据上下文为数据提供内容。
    
-or-  
    
-or-    
  
-or     
    
 
 
  1. RelativeSource:提供了可在运行时对象树中导航几个可能的关系的 Binding 的源信息。
  
  1. TemplateBinding:使控件模板能够使用模板化属性的值,这些属性来自于将使用该模板的类的对象模型定义属性。
    
 
 
  1. ColorConvertedBitmap:提供一种方法,用于指定没有嵌入的配置文件的位图源。 颜色上下文/配置文件由 URI 指定,与映像源 URI 相同。
    
 
 
  1. ComponentResourceKey和TemplateResourceKey:
    
 
 

XAML资源复用

在开发过程中,我们可以直接在按钮上进行按钮模板的定义,例如下面的代码。

   
                          
                    
                        
                            
                                
                                    
                                
                            
                            
                        
                    
                
            
        
 
 

 
                        

这样的代码在界面比较简单时,还无所谓,但是随着控件的样式越来越复杂,可能会成为一团乱麻,这对于追求优雅代码的我们来说,可能是难以忍受的,所以往往会使用资源引用来完成。

StaticResource

例如,我们可以在当前页面代码中定义对应的样式,这种样式可以使用 StaticResource 的形式引入。但是这样的引用形式,没有对象图的访问权限,意味着无法访问资源依赖的其他资源。