wpf

WPF是什么

WPF(Windows Presentation Foundation) 是微软推出的基于Windows 的用户界面框架, 属于.NET Framework 3.0的一部分。 它提供了统一的编程模型、语言和框架, 真正做到了分离界面设计人员与开发人员的工作; 它提供了全新的多媒体交互用户图形界面。

Windows Presentation Foundation 翻译为 “Windows呈现基础” Presentation 展示 Foundation 基础、基地

 

WPF的特性

微软新一代图形系统
运行在.NET Framework 3.0及以上版本
基于DirectX 9/10技术,支持GPU硬件加速,在不支持硬件加速时也可以使用软件绘制
图形向量渲染引擎
集成了矢量图形,丰富的流动文字支持(flow text support),3D视觉效果和强大无比的控件模型框架。
业务逻辑和用户界面(UI)彻底分开
任何一种.Net编程语言(C#,VB NET等开发语言)进行开发
XAML对界面的可视化控件描述、定制个性化主题、外观、行为
超强的用户体验

 

WPF驱动模式

数据驱动UI,数据是核心,处于主动的,UI从属于数据并表达数据,是被动的。 WPF中数据主动,UI被动; 数据第一,控件第二。

 

XAML

XAML语言:是微软公司为构建应用程序用户界面而创建的一种新的“可扩展应用程序标记语言”,提供了一种便于扩展和定位的语法来定义和程序逻辑分离的用户界面。

特点:
定义应用程序的界面元素
显示的声明WPF资源(样式、模板、动画等)
可扩展性(自定义UI控件)
集中关注于界面的设计和实现

 

WPF应用程序组成

app.config 配置文件 ----连接字符串、配置信息
App.xaml 设置应用程序起始文件与系统级资源
App.xaml.cs app.xaml文件的后台类文件 ,继承自Application,封装整个WPF应用程序处理
MainWindow.xaml Window ----WPF应用程序界面与Xaml设计文件
MainWindow.xaml.cs ---xaml窗口文件的后台代码文件

 

XAML命名空间

XAML和.NET其他语言一样,也是通过命名空间有效组织起XAML内部的相关元素类,这里的命名空间与.NET中的命名空间不是一一对应的,而是一对多,一眼望去,都是“网址”,这里的网址,是遵循XAML解析器标准的命名规则,而不是真正的网址. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" --默认命名空间(所有WPF类,包括构建用户界面使用的控件)
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" --对应一些与XAML语法和编译相关的CLR名称空间
<Style x:key="buttonMouseOver" TargetType="{x:Type Button}">
xmlns和xmlns:x的区别在于,x作为别名,在应用时,以前缀形式出现,而xmlns作为默认命名空间,不使用前缀标识的元素,来自该命名空间(默认命名空间)。

 

XAML命名空间的语法

1. xmlns[:可选映射前缀]="命名空间描述"
注意:没有加可选映射前缀的xmlns是WPF默认的命名空间,一个xaml文件只能有一个默认的命名空间
一个完整的xaml文件,必须具备 以上两个命名空间,因为不可能不用到WPF和XAML类库。

2、自定义类或程序集映射语法 xmlns[:必选映射前缀]="clr-namespace:[命名空间];assembly=[程序集名称]"

 

Window

Window:WPF 应用程序窗口
作用:托管使数据可视化并使用户能够与数据交互的内容。
WPF 应用程序使用Window类提供自己的窗口

窗口分为两个区域:非工作区和工作区。
非工作区:边框、标题栏、图标、“最小化”、“最大化”和“还原”按钮。“关闭”按钮、“系统”菜单
工作区:窗口非工作区内的区域,开发人员使用它来添加特定于应用程序的内容,例如菜单栏、工具栏和控件。

在 WPF 中,窗口可用于:
显示窗口。
配置窗口的大小、位置和外观。
托管特定于应用程序的内容。
管理窗口的生存期。

在 WPF 中,可以使用代码或XAML标记实现控制窗口的外观和行为。但一般情况下,外观使用xaml标记实现,行为使用代码实现

 

Window标记与代码协同工作

1.在标记中, Window元素必须包含x:Class属性。 生成应用程序后x:Class ,标记文件中存在会导致 Microsoft 生成引擎(MSBuild)创建一个partial派生自Window的类,并具有由x:Class属性指定的名称。 这要求为XAML架构( xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" )添加 XML 命名空间声明。 生成partial的类实现InitializeComponent方法,该方法用于注册事件并设置标记中实现的属性

2.在代码隐藏中,类必须与x:Class属性指定的类同名,并且必须派生自Window。 在生成应用程序时将代码隐藏文件与partial为标记文件生成的类相关联

3.在代码隐藏中, Window该类必须实现调用InitializeComponent方法的构造函数。 InitializeComponent由标记文件的生成partial类实现,用于注册事件和设置在标记中定义的属性。

 

Window生存期

窗口也有生存期,开始于首次实例化窗口, 在这之后将打开、激活、停用直至最终关闭窗口。
在实例化窗口时,对它的引用会自动添加到由该Application对象管理的窗口的列表中。
此外,默认情况下,第一个要实例化的窗口是由Application设置为主应用程序窗口
window.Show() 打开窗口(无模式窗口,允许用户在同一应用程序中激活其他窗口)
ShowDialog 以模式化打开 windows,如对话框(必须关闭才能激活其他窗口)
Close() 关闭窗口

 

Window属性

WindowStartupLocation:窗口首次显示时的位置
ShowInTaskbar 窗口是否具有任务栏按钮
WindowState 指示窗口是最大化、最小化或正常尺寸显示
Topmost 是否在最顶层
Icon 窗口图标
WindowStyle 窗口的边框样式
ResizeMode 窗口的调整模式
Title 窗口标题
ShowActivated 首次显示是否激活窗口,默认true,false的话,窗口会隐藏

 

WPF控件

 

WPF控件分类

布局控件:容器控件,排列和组织其他控件,其父类是Panel

内容控件:只能容纳一个控件或布局控件作为他的内容,父类是ContentControl.

带标题内容控件:同上,可以加一个标题,父类是HeaderedContentControl

条目控件:可以显示一列数据,一般数据类型相同,父类是ItemsControl

带标题条目控件 同带标题内容控件类同,父类是HeaderedItemsControl

特殊内容控件 这类控件比较独立,但也比较常用,如TextBox,TextBlock,Image等。

 

常用控件

ContentControl

内容控件只能容纳一个控件或布局控件作为他的内容

属性:
Content 内容对象
ContentTemplate 用来显示的内容的数据模板 DataTemplate

 

Label 文本标签

父类 ContentControl --Content

<Label Content="姓名:" HorizontalAlignment="Left" Margin="42,35,0,0" VerticalAlignment="Top" Width="57"/>

Content: Label中的内容--文本或其它控件

<Label HorizontalAlignment="Left" Margin="42,35,0,0" VerticalAlignment="Top" Width="57">
            <Label.Content>
                <TextBlock>用户名</TextBlock>
            </Label.Content>
</Label>

应用:  用作文本显示

 

 

TextBox 文本框

编辑与显示 父类 TextBoxBase --Control 特殊内容控件

<TextBox Name="txtUName" HorizontalAlignment="Left" Height="23" Margin="138,26,0,0" TextWrapping="NoWrap" Text="admin" VerticalAlignment="Top" Width="120"/>

TextWrapping 换行方式

Text 文本内容

TextAlignment 文本的对齐方式

<TextBox x:Name="txtUName" HorizontalAlignment="Left" Height="23" Margin="104,38,0,0" TextWrapping="NoWrap"  VerticalAlignment="Top"  Width="120" >
            <TextBox.Text>aaaa</TextBox.Text>
</TextBox>

应用: 编辑与显示文本信息

 

TextBlock

TextBlock 实际上指的就是System.Windows.Controls.TextBlock类,它是一个用于显示少量流内容的轻量控件。其中包含一个InLines属性,支持 Inline 流内容元素的承载和显示。 

 <TextBlock Name="tbTxt"   TextWrapping="Wrap" Text="今天的课程内容是:WPF TextBlock" Foreground="Red" FontWeight="Bold" FontFamily="仿宋" HorizontalAlignment="Left" />

用于 显示文本信息、常用作为内容控件的内容呈现控件

 

 

PasswordBox 密码框

父类 Control 特殊内容控件

<PasswordBox Name="txtUPwd" HorizontalAlignment="Left" Height="23" Margin="138,60,0,0" Password="123456" PasswordChar="*"  VerticalAlignment="Top" Width="120"/>

 Password 密码文本信息 

PasswordChar 密码字符

事件:PasswordChanged  密码改变时发生

应用: 密码输入,以密码字符显示

 

 

Button  按钮

父类ContentControl --Content

 <Button Name="btnClose"  Content="关闭" HorizontalAlignment="Left" Margin="170,255,0,0" VerticalAlignment="Top" Width="53" Click="BtnClose_Click" Command="" />

Content 按钮内容

Click 按钮单击事件

IsDefault 按下Enter时相当于点击按钮

IsCancel 按下Esc时相当于点击按钮

Command 按此按钮时调用的命令。

注册事件:在xaml代码中,通过代码注册; 在设计视图中,双击按钮注册;选中控件,在属性面板中,点击闪电符号双击事件名右边的空白处注册

应用: 响应执行操作,一般注册Click事件或配置Command

 

 

Border 边框

父类是Decorator

边框,围绕在其他元素周围或背景色

BorderBrush 边框颜色

BorderThickness 粗细

CornerRadius 圆角的弧度

Background border内部背景色

应用:布局面板一起使用,作为任意控件的边框显示

 

 

RadioButton 单选按钮

ToggleButton(切换按钮)-- ContentControl --Content

单选按钮在同一组中,互斥(只有一个选中),不同组,不互斥

 <RadioButton Name="rbtnMale" Content="男" GroupName="sex" IsChecked="True" Margin="104,70,0,0"/>

Content 按钮内容   

GroupName 组名     

IsChecked 单选按钮的选中状态

事件:Checked 已选中时发生   UnChecked 未选中时发生  Click 单击时

应用: 一组选项中,只能从中选择一个的情况 ,状态、性别等设置

 

 

CheckBox 复选框

ToggleButton  父类ContentControl --Content

 一组选项中,允许可以选择多个

<CheckBox  Margin="104,100,0,0" Content="大学英语"  />
<CheckBox Content="高等数学"  Margin="180,100,0,0" />
<CheckBox Content="C#程序设计"  Margin="260,100,0,0" />
<CheckBox Content="SQL Server数据库"  Margin="350,100,0,0" /> 

Content 复选框内容       

IsChecked 单选按钮的选中状态   

事件:Checked 已选中时发生   UnChecked 未选中时发生  Click 单击时

应用: 一组选项中,可以从中选择一个或多个的情况,兴趣、角色设置、人员选择等

 

 

ComboBox 下拉框 Selector --ItemsControl (条目控件--用于呈现项的集合)

ListBox 列表框 Selector --ItemsControl

 

Image 图像控件

FrameworkElement UIElement

表示用于显示图像的控件

<Image Name="imgPhoto" StretchDirection="DownOnly" Height="80" Width="80" Stretch="Fill"  /> 

tretchDirection 如何缩放

Source 图像源(ImageSource:BitmapSource/DrawingSource)

Stretch 拉伸方式 Fill(不保持纵横比)  Uniform(保持纵横比)UniformToFill(保持纵横比,如与目标纵横比不一致,对源内容剪裁)

StretchDirection DownOnly 仅缩小 UpOnly 仅放大 Both 根据Stretch模式进行拉伸

Source 图片文件路径:绝对、相对

//设置相对路径
img0.Source = new BitmapImage(new Uri("Imgs/house1.jpg", UriKind.Relative));   

//绝对路径
imgSet.Source = new BitmapImage(new Uri("pack://application:,,,/Imgs/house2.jpg", UriKind.Absolute));
imgSet.Source= new BitmapImage(new Uri("pack://siteoforigin:,,,/Imgs/house3.jpg", UriKind.Absolute));

BitmapImage 提供一个专用的 System.Windows.Media.Imaging.BitmapSource

Uri提供统一资源标识符 (URI) 的对象表示形式和对 URI 各部分的轻松访问。

文件路径访问:pack uri方案 格式:pack://授权/路径

授权:aplication/ siteoforigin

application:pack://application:,,,即 application:///

编译到库或者可执行的WPF程序集的文件(Resource,Page等)

siteoforigin: pack://siteoforigin:,,, siteoforigin:///

和WPF程序不具有关联的数据文件(访问的是应用程序启动位置里的文件,可以直接copy到该处) 如果是项目中的文件,则首先把图片文件属性的生成操作设置为内容,复制到输出目录设置为始终复制

 

DatePicker

日期控件 -----选择日期

<DatePicker Name="dtTime" DisplayDate="2020-07-08" DisplayDateStart="2020-07-04" DisplayDateEnd="2020-08-31" FirstDayOfWeek="Monday" IsDropDownOpen="False" IsTodayHighlighted="True" Text="2020-07-09" Template="{StaticResource dtStyle}"    />

DisplayDate 要显示的日期

DisplayDateStart 可以选择的开始日期

DisplayDateEnd 可以选择的结束日期

FirstDayOfWeek 每周的第一天

IsTodayHighlighted 今天是否高亮度显示

Template 设置控件的控件模板

 

Calendar

日历控件,显示月历,选择 日期或日期范围

<Calendar Name="calendarTime"  DisplayDate="2020-07-10" IsTodayHighlighted="False" FirstDayOfWeek="Tuesday" DisplayDateStart="2022-1-1" DisplayDateEnd="2022-12-31" SelectionMode="MultipleRange" DisplayMode="Month"  SelectedDate="2022-01-13" SelectedDatesChanged="CalendarTime_SelectedDatesChanged"  />

DisplayDate 要显示的日期

DisplayDateStart 可以选择的开始日期

DisplayDateEnd 可以选择的结束日期

FirstDayOfWeek 每周的第一天

IsTodayHighlighted 今天是否高亮度显示

Template 设置控件的控件模板

SelectionMode 选择日期的模式

DisplayMode 显示的模式 Decade Month Year

 

Slider 

滑块 通过沿一个轨迹移动,实现控件从一个值范围中进行选择 父类:RangeBase

用于:调整其他对象的属性值或进度

<Slider Name="slider1" HorizontalAlignment="Left" Margin="430,310,0,0" VerticalAlignment="Top" Width="215" Value="50"  Minimum="0" Maximum="100" Orientation="Horizontal" TickPlacement="Both" TickFrequency="5" IsSelectionRangeEnabled="True" SelectionStart="20" SelectionEnd="55" IsSnapToTickEnabled="True"  LargeChange="10" IsDirectionReversed="True" />

IsDirectionReversed 水平向左 垂直向下

<TextBlock Name="tbSliderVal" TextWrapping="Wrap" Text="{Binding ElementName=slider1,Path=Value}" VerticalAlignment="Top"/>

 

Dispatcher

作用是用于管理线程工作项队列。

主线程负责接收输入、处理事件、绘制屏幕等工作,这样一来,UI界面是主线程创建的,因为子线程不能直接更新由主线程维护的UI界面,所以调用Dispatcher更新UI。

WPF中的控件类都是从System.Windows.Threading.DispatcherObject继承而来, 而DispatcherObject又在构造时与当前线程的Dispatcher关联起来

由于:界面元素只有被创建它的线程访问,如果我们想在后台或者其他线程里更新UI该怎么办?利用Dispatcher的Invoke和BeginInvoke,作用就是把委托放到界面元素关联的Dispatcher里的工作项里,然后此Dispatcher关联的线程进行执行。

Invoke是在关联的线程里同步执行委托, 而BeginInvoke是在关联的线程里异步执行委托

 

ProgressBar

进度条 ——操作的进度  父类RangeBase  具有特定范围的值的元素

<ProgressBar Name="pbar1" HorizontalAlignment="Left" Height="105" Margin="55,220,0,0" VerticalAlignment="Top" Width="75" Maximum="100" Minimum="0" Value="35" Orientation="Vertical" IsIndeterminate="False" ValueChanged="Pbar1_ValueChanged"/>

Maximum 最大值

Minimum 最小值

Orientation 进度条的方向 (水平或垂直)

IsIndeterminate 是否显示当前值(false 显示当前值)

 

stackPanel面板

布局面板,父类Panel——布局与排列WPF应用程序子对象。 可以呈放多个控件。

将子元素排列成水平或垂直的一行。超出部分将隐藏,不能自动切换到下一行。子元素依次排列,位置不能随意拖动,但可以通过margin设置各子元素的间隔。

常用属性:
Orientation 该值指示子元素的堆叠方向 水平或垂直,默认垂直(Vertical)
VerticalAlignment 垂直停靠方式,
HorizontalAlignment 水平停靠方式
FlowDirection 子元素在父容器中的流动方向 (针对Orientation 为Horizontal时有效)

StackPanel可以嵌套,一个StackPanel中可以包含多个StackPanel,作为它的子元素

用于:将一系列元素排列成一行或一列,常结合其他控件或布局控件一起使用

 

WrapPanel面板

将子元素按顺序排列,从左到右或从上到下,当超过宽度或高度时,后续元素显示将自动换行。这将弥补了StackPanel显示不全的缺点。

常用属性:
Orientation 该值指示子元素的排列方向 水平或垂直,默认垂直(Vertical)
ItemWidth 每一项宽度
ItemHeight 每一项的高度

用于:将一系列元素排列成一行或一列,宽度或高度不够显示,自动切换到下一行或列

 

Canvas面板

定义一个区域,可在其中使用相对于 Canvas 区域的坐标以显式方式来定位子元素。

常用属性:
Left Right Top Bottom 附加属性 设置元素的左 右 上 下 坐标
ClipToBounds 是否剪切此元素的内容

他是布局控件中最为简单的一种,直接将元素放到指定位置,使用Canvas,必须指定一个子元素的位置(相对于画布),否则所有元素都将出现在画布的左上角。调整位置用Left、Right、Top和Bottom四个附加属性。如果Canvas是窗口主元素(即最外层的布局面板是Canvas),用户改变窗口大小时,Canvas也会随之变化,子元素的位置也会随之移动,以保证相对于Canvas的位置属性不变。
Canvas允许子元素的部分或全部超过其边界,默认不会裁剪子元素,同时可以使用负坐标,即溢出的内容会显示在Canvas外面,这是因为默认 ClipToBounds=”False”
两个元素重叠,后添加的在上面,先添加在下面。可以通过设置Panel.Index来调整先后顺序,Index值越大,就显示在上边,越小就显示在下边
如果同时设置了Left Right,只应用Left,不管先后顺序。同理,Top,Bottom优先应用Top

用于:主要来布置图面。

 

DockPanel面板

定义一个区域,从中可以按相对位置水平或垂直排列各个子元素。

常用属性:
LastChildFill 指示最后一个子元素是否拉伸以填充剩余的可用空间
Dock 附加属性 设置停靠的位置

停靠面板类似于WinForm中控件的Dock属性。DockPanel会对每个子元素进行排序,并将根据指定的边进行停靠,多个停靠在同侧的元素则按顺序排序。在DockPanel中,指定停靠边的控件,会根据定义的顺序占领边角,所有控件绝不会交叠。
默认情况下,后添加的元素只能使用剩余空间,无论对DockPanel的最后一个子元素设置任何停靠值,该子元素都将始终填满剩余的空间。如果不希望最后一个元素填充剩余区域,可以将DockPanel属性LastChildFill设置为false,还必须为最后一个子元素显式指定停靠方向。

用于:布局自适应页面   有优先级:先写的,先占有边角

 

Grid面板

Grid  定义由列和行组成的灵活的网格区域。

常用属性:
ShowGridLines 显示网格线
附加属性 :Row Column RowSpan ColumnSpan
RowDefinitions ColumnDefinitions

使用Grid,首先要向RowDefinitions和ColumnDefinitions属性中添加一定数量的RowDefinition和 ColumnDefinition元素,从而定义行数和列数;而放置在Grid面板中的控件元素都必须显示采用Row和Column附加属性定义其放置所在的行和列,这两个属性的值都是从0开始的索引数,如果没有显式设置任何行或列,Grid将会隐式地将控件加入在第0行第0列。

注意:尽管Grid面板被设计成不可见的,但可将Grid.ShowGridLines属性设置为True,从而更清晰的观察Grid面板,方便调试,可以更准确地控制Grid面板如何选择列宽和行高。

Grid面板支持以下三种设置尺寸的方式:绝对数值(100)、自动设置(auto)、按比例设置(N*)

用于:布局页面,常结合其它布局面板一起使用

 

WPF资源

WPF资源系统 是一种保管一系列对象(如常用的画刷、样式或模版)的简单办法,从而使您更容易地复用这些对象。
我们可以在代码中以及在标记中的各个位置定义资源(或特定的控件、窗口中定义,或在整个应用程序中定义)。
资源具有如下优点:
高效——定义好资源可以在多个地方复用。
可维护性——易于修改。
适应性——可以动态修改。

资源集合:每个元素都有Resources属性,该属性存储了一个资源字典集合(它是ResourceDictionary类的实例)。资源集合可包含任意类型的对象,并根据字符串编写索引(key)。

 

分类

资源分为:控件资源、窗口资源、应用程序资源、系统资源

应用程序资源:如果在控件或窗口或页面找不到指定的资源。WPF会继续查找为应用程序定义的资源。定义在App.xaml中的Resources中。----极佳
系统资源:如果没有在应用程序资源中找到所需的资源,元素还会继续查找系统资源。
系统资源的三个类
SystemColors 访问系统颜色设置。
SystemFonts 访问字体设置。
SystemParamerers 封装了大量的设置列表,这些设置描述了各种屏幕像素的标准尺寸、键盘和鼠标设置、屏幕尺寸以及各种图形效果(如热跟踪、阴影以及拖动窗口时显示窗口内容)是否已经打开。

 

资源使用

静态资源(StaticResource):在程序载入内存时对资源的一次性使用,之后就不再访问这个资源;(运行时在代码里更改静态资源的属性,界面不会更新)
动态资源(DynamicResource):在程序运行过程中才会去访问资源。
使用动态属性:准备通过编程的方式替换对象。(运行时在代码里更改动态资源的属性,界面会更新)

 

资源的层次

每个元素都有自己的资源集合,为了找到期望的资源,WPF在元素树中进行递归搜索。只要不在同一集合中,可以使用相同的资源名。 元素内部资源→窗口级资源→应用程序级资源→系统资源

 

资源字典

每个Resources属性存储着一个资源字典集合。如果希望在整个应用程序中或多个项目之间共享资源的话,就可以创建一个资源字典。资源字典是一个简单的XAML文档,该文档就是用于存储资源的,不做其他事。

将多个资源字典合并到应用程序级资源中,整个应用程序都可使用这些资源。

 

外部资源引用

多个项目引用同一套资源库:封装一套通用资源库。
引用方式:
添加资源库项目引用
在App.xaml中将资源字典文件合并进来(路径)
在当前项目窗口中应用资源或样式

 

WPF样式

样式(Style)——组织和重用格式化选项的重要工具。不是使用重复的标记填充XAML,以便设置外边距、内边距、颜色以及字体等细节,而是创建一系列封装所有这些细节的样式,然后在需要之处通过style属性来应用样式。
样式是可应用于元素的属性值集合(就是一次性设定标签的很多attibute)。使用资源的最常见原因之一就是保存样式
先前使用资源,虽然也设置了控件的外观,但标记变得繁琐,还没有不使用简洁,为了解决这一问题,可以独立的把该控件的要设置的属性封装到样式中。

<Style x:Key="lblLabelStyle">
       <Setter Property="Control.Foreground" Value="Black"></Setter>
       <Setter Property="Control.BorderBrush" Value="Green"></Setter>
</Style>
<Label Content="用户名:"  Style="{StaticResource lblLabelStyle}" />

 

嵌套元素

每个Style对象都封装了一个Setter对象的集合。每个Setter对象设置元素的单个属性。在某些情况下不能使用简单的特性字符(指字符串)设置属性值。可使用嵌套的元素(指属性标签)代替(注:指某个标签的attibute是一个复杂类型,不是一个字符串可以描述,就使用标签去创建该复杂类型的对象

<Setter Property="Control.Background">
        <Setter.Value>
              <SolidColorBrush Color="Green"/>         
       </Setter.Value>
</Setter>

 

封装特定元素类型的样式

常常会为某个特定类型元素封装样式,如果不定义Key,会自动应用,若某一控件不想应用这一样式,需要设置Style=”{x:Null}”
如果定义key,通过key去应用。

<Style x:Key="btnStyle2" TargetType="Button">
            <Setter Property="FontFamily" Value="微软雅黑"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Foreground" Value="Green"/>
            <Setter Property="Width" Value="60"/>
            <Setter Property="Height" Value="30"/>
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Top"/>
            <Setter Property="FontWeight" Value="Bold"/>
</Style>

 

多层样式

每个WPF元素一次只能使用一个样式对象,这像是一种限制,但由于属性值的继承和样式继承特性,这种限制实际是不存在的。
比如:为一组控件使用相同的字体,又不想为其中某些控件应用完全相同的样式。对于这种情况,可以考虑将其抽象成父样式,来提升样式代码的可维护性以及减少代码冗余。(就是相同的样式提取出来写在父样式里,子样式里写自己特有的样式)
当希望在另一个样式的基础上建立样式,可用BasedOn特性进行样式继承-----多层样式

 

触发器

使用触发器可自动完成简单的样式的改变,不需要使用后台代码,也可以完成不少工作。 触发器通过Style.Trigger集合链接到样式。每个样式可以有任意多个触发器。每个触发器都是System.Windows.TriggerBase的实例。

 

简单触发器

可为任何依赖项属性关联简单触发器
每个触发器都制定了正在监视的属性以及正在等待的属性值。当属性值出现时,将应用Trigger.Setters集合里的设置器。
触发器的优点:不需要为实现他们而编写任何后台代码。

 

多条件触发器

如果希望几个条件都满足时才激活触发器,可使用MultiTrigger。在样式触发器中

要修改背景色,需要把默认控件模板中的触发器关于IsMouseOver与IsPressed效果给禁掉(冲突)

 

事件触发器

普通触发器等待属性发生变化,而事件触发器等待特定事件被引发。事件触发器要求用户提供一系列修改控件的动作。这些动作常用于动画。

 

视觉树与逻辑树

WPF 有两棵树的概念: 可视树 逻辑树, 在运行时会维护这两棵树。

可视树:界面上所有渲染在屏幕上的元素

可视树用于渲染,事件路由,定位资源(如果该元素没有逻辑父元素)等等等等。
可视树能看到控件内部的元素,这些元素一般继承自Visual类
向上或者向下遍历可视化树可以简单的使用VisualTreeHelper类和简单的递归方法。
任何承继自ContentElement的东西都可以在UI上显示,但其实并不在可视化树中。
内容元素(继承自ContentElement的类)不是可视化树的一部分;他们不是继承自Visual而且没有可视化表示。为了显示在UI上,ContentElement必须寄宿在一个Visual主体上,通常是一个FrameworkElement。你可以认为主体类似于一个可以选择如何展示该ContentElement的浏览器。

逻辑树表示UI的核心结构,就是我们看到的节点。和XAML文件中定义的元素近乎相等,排除掉内部生成的那些用来帮助渲染的可视化元素。
WPF用逻辑树来决定依赖属性,值继承,资源解决方案等。可以使用LogicTreeHelper类遍历逻辑树,但它只对DependencyObject有效,遍历逻辑树时需要非常小心,最好做类型检查。
逻辑树 始终存在于WPF的UI中,不管UI是用XAML编写还是用代码编写。
WPF的每个方面(属性、资源等等)都是依赖于逻辑树的。

可视树基本上是逻辑树的一种扩展。逻辑树的每个结点都被分解为它们的核心视觉组件。逻辑树的结点对我们而言基本是一个黑盒。而可视树不同,它暴露了视觉的实现细节
逻辑树专注于界面的核心结构,而可视树专注于界面元素的呈现细节。
WPF中提供了遍历逻辑树和可视树的辅助类:System.Windows.LogicalTreeHelper和System.Windows.Media.VisualTreeHelper。
注意遍历的位置:逻辑树可以在类的构造函数中遍历。但是,可视树必须在经过至少一次的布局后才能形成。所以它不能在构造函数遍历。通常是在OnContentRendered进行,这个函数为在布局发生后被调用。

并不是所有的逻辑树结点都可以扩展为可视树结点。只有从System.Windows.Media.Visual和System.Windows.Media.Visual3D继承的元素才能被可视树包含。其他的元素不能包含是因为它们本身没有自己的提交(Rendering)行为。

 

模板

模板——具有一定规格的样板(表现形式)。WPF中的模板同样——表现形式
在WPF中包括三种模板:控件模板、数据模板和面板模板。
它们都继承于FrameworkTemplate基类

控件模板,即控件外观外衣,自定义控件的外观表现,决定控件长什么样子注:个人理解,控件模板可以决定控件由哪些可视化元素组成,而样式仅能设置可视化元素的属性,比如颜色等
数据模板,即数据的外衣。决定数据内容的呈现方式——决定数据显示成什么样子
面板模板, 即面板的外衣,而面板又用于进行布局的,所以面板的外衣也就是布局的外衣,通过修改面板模板可以自定义控件的布局。用于指定项的布局,一般用于条目控件中。

WPF模板其实都是外观的表现形式,不管是控件模板、数据模板还是面板模板,其都是改变控件的表现形式。只不过这三种控件的作用点不一样罢了。
控件模板:针对于 控件本身,修改它可以改变控件本身表现的样子;
数据模板针对控件的数据,修改它可以改变控件绑定的数据表现样子。既然是决定数据的表现,从而决定其一般应用于数据绑定控件,如ListBox、ListView等控件。
面板模板则针对于控件的布局,修改它可以影响控件的布局方式。

 

控件模板

要修改控件模板,则首先需要了解控件的组成。
下面以Button控件为例来分析:
Button由多个可视化元素组成——
边框(由Border类表示)、
内部的容器(一个ContentPresenter对象)、
存储按钮文本的文本块控件(由TextBlock表示)。

使用控件模板非常简单:
1. 首先在资源集合中创建一个ControlTemplate,并指定key标记
2. 然后赋值到控件的Template属性中。  

ControlTemplate模板主要有两个属性:VisualTree(视觉树) 和 Triggers (触发器)
VisualTree:用于呈现所画的控件,就是定义如何画
Triggers :用于对视觉树上的元素进行一些变化效果

  <ControlTemplate x:Key="btnCTemp" TargetType="Button">
        <Grid>
            <Rectangle x:Name="br" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Stroke="Red" StrokeThickness="2" Fill="LightBlue" RadiusX="12" RadiusY="5"/>
            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
        </Grid>

          <ControlTemplate.Triggers>
               <Trigger Property="IsMouseOver" Value="True">
                      <Setter Property="Fill" TargetName="br" Value="LightGray"/>
               </Trigger>
          </ControlTemplate.Triggers>
    </ControlTemplate>

应用控件模板

 

数据模板

数据模板——数据的外衣,数据模板是一段定义如何绑定数据对象的XAML标记
有三种类型的控件支持数据模板:
内容控件,ContentTemplate属性支持数据模板。内容模板用于显示任何放在Content属性中的内容。
列表控件,即继承自ItemsControl类的控件,通过ItemTemplate属性支持数据模板。该模板用于显示由ItemsSource提供集合中的每一项。
Menu/TreeView控件,ItemTemplate属性支持分层数据模板(Hierarchical [ˌhaɪəˈrɑːkɪkl] DataTemplate)
基于列表的模板实际上是以内容控件模板为基础的,因为列表中的每一项由一个内容控件包装。如ListBox控件的ListBoxItem元素是一个ContentControl。
Menu/TreeView的项是带标题的条目控件(HeaderedItemsControl),可应用分层数据模板来定义分层数据样式。

 

内容模板定义与使用

使用DataTemplate:
1.首先在资源集合中创建一个数据模板,并设置key标签。
2.通过内容控件的ContentTemplate属性引用 key 即可。

<DataTemplate x:Key="btnDTemp">
  <TextBlock x:Name="txt" Text="{Binding }" Margin="5,0" />
  <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding}" Value="确定">
      <Setter Property="Foreground" TargetName="txt" Value="Red"/>
    </DataTrigger>
    <DataTrigger Binding="{Binding}" Value="取消">
      <Setter Property="Foreground" TargetName="txt" Value="Gray"/>
    </DataTrigger>
  </DataTemplate.Triggers>
</DataTemplate>
ContentTemplate="{StaticResource btnDTemp}"

 

条目控件项模板定义与使用

<DataTemplate x:Key="itemTemp1" DataType="{x:Type local:ClassInfo}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding ClassId}" Foreground="Green" Margin="5,0"/>
        <TextBlock Text="{Binding ClassName}" Foreground="Purple" Margin="0"/>
    </StackPanel>
    <DataTrigger Binding="{Binding ClassName}" Value="八班">
        <Setter TargetName="tbName" Property="Background" Value="Red"/>
    </DataTrigger>
</DataTemplate>
ItemTemplate="{StaticResource itemTemp1}"

 

依赖属性

依赖属性(Dependency Property),WPF引入的一种新类型的属性,在WPF中有着极为广泛的应用
在WPF中对于WPF依赖属性的使用贯穿样式的使用,数据绑定,动画等等
依赖属性: 即本身可以没有值,而依赖于其他数据源而取得值的属性
依赖属性使用 “静态共享”的方式
另外相对于普通的WPF属性,依赖属性还有如下的优势
1. 属性继承:属性值自顶向下沿着元素树进行传递
2. 改变通知,:会自动根据属性值的改变触发一系列的动作。 这样可以使我们更方便地实现应用,同时大大减少了代码量。
3. 支持多个提供者:可以通过多种方式来设置依赖属性的值。可以配合表达式、样式和绑定来对依赖属性设置值。
4.节约内存:在WinForm中,每个UI控件的属性都赋予了初始值,这样每个相同的控件在内存中都会保存一份初始值。而WPF依赖属性很好地解决了这个问题,它内部实现使用哈希表存储机制,对多个相同控件的相同属性的值都只保存一份。

 

数据绑定

WPF中的数据绑定提供了很强大的功能。与普通的WinForm程序相比,其绑定功能为我们提供了很多便利,省去了很多维护的繁琐工作.

数据绑定的关键是System.Windows.Data.Binding对象,它会把两个对象(UI对象与UI对象之间,UI对象与.NET数据对象之间)按照指定的方式粘合在一起,并在他们之间建立一条通信通道,绑定一旦建立,接下来的应用生命周期中它可以自己独立完成所有的同步工作。
根据其应用场合的不同,绑定可以分为以下几种:
对象间的绑定 UI与UI,UI与.net对象
绑定到集合 ItemsSource
数据模板 Binding
相对绑定 RelativeSource

 

UI对象之间的绑定

源对象的某个属性值绑定(拷贝)到目标对象的某个属性上。
源属性——任意类型,目标属性——必须是依赖属性(Dependency Property)。
通常情况下,UI对象间的绑定,源属性和目标属性都是依赖属性 (有些属性不是) ,因为依赖属性有垂直的内嵌变更通知机制,WPF可以保持目标属性和源属性的同步。
绑定语法:"{Binding ElementName=txtBox,Path=Text}" TextBox Checkbox
ElementName:源对象 Path 源属性 Mode 绑定模式:TwoWay(源和目标互相影响)  OneWay(源影响目标,目标改变不影响源)  OneWaytoSource(目标影响源,源改变不影响目标) OneTime

 

绑定到集合

绑定到集合——以数据驱动为主的应用时最经常用到的绑定方式。

WPF支持任何类型的.NET对象作为数据源绑定到WPF对象.
对于所有的ItemsControl对象都有一个ItemsSource依赖属性,这是专门为数据绑定而准备的。ItemsSource的类型是IEnumerable,所以对于我们几乎所有的集合类型我们都可以轻易的改变成ItemsSource的源对象。

ItemsSource=”{Binding Path =”属性名”}”(注:path的作用是,指定控件里每个条目,要绑定源集合里每个对象的哪个属性

对于.NET集合/对象来讲,它不具备这样的能力——UI目标属性与源数据同步。
为了让目标属性与源集合的更改保持同步,源集合必须实现一个叫INotifyCollectionChanged的接口,但通常我们只需要将集合类继承于ObservableCollection类即可。因为ObservableCollection实现了INotifyPropertyChanged和INotifyCollectionChanged接口

ListBox ComBoBox ListView DataGrid Menu TreeView TabControl.....

DataContext是数据上下文对象,它是为了避免多个对象共享一个数据源时重复的对所有对象显式地用binding标记每个Source/RelativeSource/ElementName,而把同一个数据源在上下文对象的某个范围内共享,这样当一个绑定没有显式的源对象时,WPF会遍历逻辑树找到一个非空的DataContext为止(注:数据源默认绑定控件的DataContext属性

ItemsSource=”{Binding}” 设置ItemsControl的数据源为DataContext

对于集合的绑定,通常会需要用到以下几个标记:
DisplayMemberPath 指定源对象中被显示的属性。(注:DisplayMemberPath的作用是,指定控件里每个条目,要绑定源集合里每个对象的哪个属性
ItemsSource 指定要绑定的数据源
ItemTemplate 指定以什么样的格式来显示数据
Path 数据源对象中的属性—控制显示
DataContext 共享数据源

 

 

 

WPF布局基础

WPF布局原则

一个窗口中只能包含一个元素
不应显示设置元素尺寸
不应使用坐标设置元素的位置
可以嵌套布局容器


WPF布局容器

StackPanel:水平或垂直排列元素、Orientation ([ˌɔːriənˈteɪʃn] 方向) 属性分别:Horizontal ([ˌhɒrɪˈzɒntl] 水平的)/ Vertical ([ˈvɜːtɪkl] 垂直的)
WrapPanel:水平或垂直排列元素、针对剩余空间不足会进行换行或换列进行排列
DockPanel:根据容器的边界、元素进行Dock.Top,Left,Right,Botom设置
Grid:类似table表格、可灵活设置行列并放置控件元素、比较常用
UniformGind:指定行和列的数量,均分有限的容器空间
Canvas:使用固定的坐标设置元素的位置、不具备铺定停靠等功能。

 

Grid

为最常用的布局容器,作为View中的主要组成部分,负责框架中整体的页面布局。
ShowGridLines:可以设置行业的边距线的显示。
Grid.RowDefinitions:可以创建任意行,进行固定高度与百分比或自适应高度设置。
Grid.ColumnDefinitions:可以创建任意列,进行固定宽度与百分或自适应宽度设置。

 

样式Style

WPF中的各类控件元素,都可以自由设置其样式。
·诸如:·字体(FontFamily)、·字体大小(FontSize)、·背景颜色(Background)、·字体颜色(Foreground)、边距(Margin)、·水平位置(HorizontalAlignment)、垂直位置(VerticalAlignment)等等。
而样式则是组织和重用以上的重要工具。不是使用重复的标记填充XAML,通过Styles创建一系列封装所有这些细节的样式,然后通过Style属性应用封装好的样式。这点类似于CSS样式。然而,WPF样式的功能更加强头,如控件的模板、触发器等等。

触发器

当达到了触发的条件,那么就执行预期内的响应,可以是样式、数据变化、动画等。可以为单独的控件设置,但往往声明在样式里
触发器通过Style.Triggers集合连接到样式中,每个样式都可以有任意多个触发器,并且每个触发器都是System.Windows.TriggerBase的派生类实例,以下是触发器的类型:
Trigger:监测依赖属性的变化、触发器生效
MultiTrigger:通过多个条件的设置、达到满足条件、触发器生效
DataTrigger:通过数据的变化、触发器生效
MultiDataTrigger:多个数据条件的触发器
EventTrigger:事件触发器,触发了某类事件时,触发器生效。

 

控件模板

控件模板用于来定义控件的外观、样式,还可通过控件模板的触发器(ControlTemplate.Triggers)修改控件的行为、响应动画等
对与WPF当中,每个控件都是无外观的,这意味着我们可以完全自定义其可视元素的外观,但是不能修改其内部的行为,因为控件的行为已经被固定在控件的具体类中。
在Winform当中,你会发现,控件的外观与行为都被固定在控件的具体类中,当我们想要修改按钮的的边框弧度、或者修改控件本身一些细节的时候,我们需要修改外观的同时,把原来具备的所有行为重写一遍,我们大多数称之为自定义控件。

 

posted on 2023-05-26 00:13  drewwestlhq  阅读(80)  评论(0编辑  收藏  举报

导航