WPF复习知识点记录

由于近几年主要在做Web项目,客户端的项目主要是以维护为主,感觉对于基础知识的掌握没有那么牢靠,趁着这个周末重新复习下WPF的相关知识。

文章内容主要来自大佬刘铁锰老师的经典著作《深入浅出WPF》。


(相关资料图)

因为是复习,所以知识内容不会一一记录,如有需要了解更多可以看书中内容。

注意:博客中的代码示例我是以avalonia为UI框架写的。代码可能部分跟WPF的稍有不同。

1.从零起步认识XAML

1.什么是XAML

XAML(读作zaml)是WPF技术中专门用于设计UI 的语言

2.优点

实现界面与代码的分离

可以设计出专业的UI和动画

基于XML的标记语言,简单易懂,结构清晰

剖析

1.最简单的XAML代码

<Window xmlns="/winfx/2006/xaml/presentation"></Window>

这个示例中,Window是一个XAML元素,它表示窗口组件。xmlns属性定义了XML命名空间,即指明XAML所使用的命名空间。在这里,/winfx/2006/xaml/presentation是WPF的命名空间。

这个示例中的XAML代码只有一个Window元素,它是一个空的容器。可以在Window元素中添加其他界面元素,例如按钮、文本框等,来构建应用程序的用户界面。同样,可以在XAML中设置属性来更改元素的外观和行为。

和attribute

先不说WPF中两个属性的定义,我们先看看对应一个类的对象。

1)属性是指类体里用get或set封装好的属性。属性是面向对象的理论范畴。比如说一个盒子,盒子的高度,长度,都是这个盒子的属性。在C#中实现的时候可以通过GET SET 封装。

2)特性是指应用于类,字段,方法,接口的进一步说明,用专业的术语就是给类,字段,方法,接口补充元数据,说的再白一点就是给它们打上标记,打了标记后编译器就知道如何来编译它。特性是属于编程语言层面的东西。比如2个相同的类,为了表示这2个类不完全相同或者有差异。这时候就要针对这两个类加一些特性。

[Serializable]                                   // 这是Attribute,打上该标记的类说明可以被序列化class Order{   protected internal Single Price { get; set; } // 这是Property   [Obsolete("此方法已过时,请改用xxx.")]           // 打上该标记说明此方法是过时的   public Single GetPrice()   {      return default(Single);   }}

在看在XAML中:

Attribute在XAML中的对于标签的属性特征,以下都是Window标签下的attribute

xmlns="/avaloniaui"xmlns:x="/winfx/2006/xaml"xmlns:vm="using:"xmlns:d="/expression/blend/2008"xmlns:mc="/markup-compatibility/2006"mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"x:Class=""x:DataType="vm:MainWindowViewModel"xmlns:md="clr-namespace:;assembly="Icon="/Assets/"Title="AvaloniaMarkdown"

Property在后台代码中针对对象的属性特征,对应的后端类的对象Text,就是一个 property:

private string _text="hello";public string Text{    get => _text;    set => (ref _text, value);}private string _filePath;

名称空间

xmlns[:可选的映射前缀]="名称空间"

用于引用外来程序集

xmlns="/avaloniaui"xmlns:x="/winfx/2006/xaml"xmlns:vm="using:"

没有映射前缀的是默认名称空间,默认名称空间只能有一个。

通过xmlns,我们可以直接使用这些CLR名称空间中的类型

关键字

XAML文件对应的.文件中的类的声明使用了partial关键字,可以把一个类拆分在多处定义,只要各部分代码不冲突即可,由于partial机制,我们实现逻辑代码留在.cs文件中,把UI元素相关代码分离出去。

public partial class MainWindow : Window{    public MainWindow()    {        InitializeComponent();    }}

语法

1.树形结构

<Window><Grid><><ColumnDefinition Width="10*"/><ColumnDefinition Width="10*"/></><><RowDefinition Height="1*"/><RowDefinition Height="10*"/></><Grid ="0"            ="0" ="2"><><ColumnDefinition Width="1*"/><ColumnDefinition Width="9*"/></><StackPanel ="0" ><Button>打开</Button><Button>保存</Button><Label/></StackPanel></Grid><TextBox ="1" ="0"/><md:MarkdownScrollViewer ="1"            ="1"/></Grid>  </Window>

XAML UI 框架是树状结构,以对象为根节点,一层一层往下包含。我们经常需要在这棵树上进行按名称查找元素、获取父子节点等操作。WPF使用VisualTreeHelper、LogicalTreeHelper来操作树。

:Name

x:Name的作用:

告诉XAML编译器,带有x:Name的标签需要声明一个引用变量,变量名就是x:Name的值

将XAML标签对应的对象的Name属性也设为x:Name的值,并注册到UI树上,方便查找

:Key

在资源字典(Resource Dictionary)中使用,构成其中的元素。资源(Resource )非常重要,存放需要重复使用的内容。

<><Color x:Key="SystemAccentColor">rgb(155, 138, 255)</Color><Color x:Key="SystemAccentColorDark1">rgb(155, 138, 255)</Color><Color x:Key="SystemAltMediumLowColor">rgb(52, 53, 65)</Color><Color x:Key="ApplicationPageBackgroundThemeBrush">rgb(52, 53, 65)</Color><Color x:Key="ControlStrokeColorDefaultBrush">rgb(94, 95, 109)</Color></>

3.控件

单一内容控件

只能单一元素充当其内容。

例如:Button、Label等(具体看书中列表)

除了用于显示主体内容的区域外,控件还具有一个显示标题(header)的区域

例如:GroupBox、TabItem

显示列表化的数据

内容属性为Items或ItemsSource

每种ItemsControl都对应有自己的条目容器(Item Container)

例如:ListBox、TreeView

在UI 上起装饰效果,比如可以使用Border元素为一些组织在一起的内容加个边框

例如:Border、ViewBox

和TextBox

最常用的文本控件

TextBlock 用于显示文本,不能编辑

TextBox 允许编辑内容

绘制图形使用的元素

Fill 属性设置填充

Stroke 属性设置边线

所有的UI布局元素都属于这一族

Panel元素控制布局

包括:Canvas、Grid、StackPanel等

4.布局

WPF的UI形成的树形结构,我们称之为可视化树(Visual Tree)

控件框架形成的树形结构,我们称之为逻辑树(Logic Tree)

五种大类

Grid 网格面板

DockPanel 停靠面板

StackPanel 栈面板

WrapPanel 环绕面板

Canvas 精准定位

下面复习下它们的使用方法:

网格形式布局

定义多少列

定义了多少行

<Grid><><ColumnDefinition Width="10*"/><ColumnDefinition Width="10*"/></><><RowDefinition Height="1*"/><RowDefinition Height="10*"/></><Grid ="0"            ="0" ="2"><><ColumnDefinition Width="1*"/><ColumnDefinition Width="9*"/></><StackPanel ="0" Orientation="Horizontal" HorizontalAlignment="Center"><Button Classes="small" Margin="0,0,20,0" Command="{Binding UploadCommand}">打开</Button><Button Classes="small" Margin="0,0,20,0" Command="{Binding SaveCommand}">保存</Button><Label Content="{Binding FilePath}" Margin="0,0,20,0"/></StackPanel></Grid>

长宽常用设置值

绝对值:double 数值后加单位后缀

比例值:double数值后加一个星号(*)(如上例)

自动值:Auto

StackPanel可以把内部的元素在纵向或横向上紧凑排列,形成栈式布局

适合场合:

同类元素需要紧凑排列(列表或菜单)

移除其中的元素后能够自动补缺的布局或者动画

1.属性

常用属性数据类型可选值说明OrientationOrientationHorizontal(水平排列)\Vertical(垂直排列)决定内部元素是水平还是垂直排列,默认值(Vertical)BackgroundBrush背景色(Red/Yellow等等)HorizontalAlignmentHorizontalAlignmentCenter(中心)/Left(靠左)/Right(靠右)/Stretch(拉伸以填充父元素)决定内部元素在水平方向的对齐方式VerticalAlignmentVerticalAlignmentTop(上方)/Center(中心)/Bottom(下方)/Stretch(拉伸以填充父元素)决定内部元素在垂直方向的对齐方式

画布,可以使用Left、Top、Right、 Bottom。内部元素通过离上下左右的距离控制元素在布局中的位置。

DockPanel会对每个子元素进行排序,并停靠在面板的一侧,多个停靠在同侧的元素则按顺序排序,。

<Grid>    <DockPanel Width="Auto" Height="Auto">        <Button ="Left" >1</Button>        <Button ="Top">2</Button>        <Button ="Right">3</Button>        <Button ="Bottom">4</Button>    </DockPanel></Grid>

流式布局,根据Orientation属性来设置其水平或垂直布局方向

默认是水平排列

<WrapPanel>    <Button />    <Button />    <Button />    <Button />    <Button />    <Button /></WrapPanel>

垂直排列

<WrapPanel Orientation="Vertical"></WrapPanel>

绑定

数据交互核心属性,在字段定义的set语句中使用一个PropertyChanged事件,,当为Binding设置了数据源后,就会自动侦听PropertyChanged事件

WPF

using    private string _searchKeyword;public string SearchKeyword{    get => _searchKeyword;    set => SetProperty(ref _searchKeyword, value);}

Avalonia

using ReactiveUI;private string _filePath;public string FilePath {    get => _filePath;    set => (ref _filePath, value);}

Property 依赖属性

依赖属性是一种本身没有可以没有值,能通过使用Binding从数据源获取值的属性。拥有依赖属性的对象称为“依赖对象”

特点包括:

节省实例对内存的开销

属性值可以通过Binding依赖在其他的对象上

Property 附加属性

附加属性,被环境赋予的属性,作用是将属性与数据类型(宿主)解耦,让数据类型的设计更加灵活

<Grid><><ColumnDefinition Width="10*"/><ColumnDefinition Width="10*"/></><><RowDefinition Height="1*"/><RowDefinition Height="10*"/></><Grid ="0"            ="0" ="2"><><ColumnDefinition Width="1*"/><ColumnDefinition Width="9*"/></><StackPanel ="0" ><Button>打开</Button><Button>保存</Button><Label/></StackPanel></Grid><TextBox ="1" ="0"/><md:MarkdownScrollViewer ="1"            ="1"/></Grid>

上面 TextBox 的,都是附加属性。

和Event 路由事件

路由事件被激发后是沿着Visual Tree传递的,只有这样,“藏”在Templete里的控件才能把消息送出来。

资源

每个WPF的界面的元素都具有一个名为Resources的属性,这个属性继承自FrameWorkElement类,其类型为ResourceDictionary,用来存储资源。

<><ResourceDictionary><><ResourceInclude Source="/Assets/Lang/" /></></ResourceDictionary></>

在使用资源时候分为静态资源(StaticResource)和动态资源(DynamicResource)

在程序载入内存时对资源一次性使用,之后就不再去访问这个资源了

<TextBox ="4"   Name="Editor3"   AcceptsReturn="True"   Text="{Binding Source={StaticResource VMLocator}, Path=,Mode=TwoWay}"   FontSize="{Binding Source={StaticResource VMLocator}, Path=}" />

程序运行过程中仍然会去访问资源

<Rectangle Name="PART_BottomRightCorner"   Fill="{DynamicResource DataGridScrollBarsSeparatorBackground}"   ="2"   ="2" />

模板

控制器模板

<ControlTemplate><Border Name="DataGridBorder"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="{TemplateBinding CornerRadius}"><Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,*,Auto,Auto"><DataGridColumnHeader Name="PART_TopLeftCornerHeader"  Theme="{StaticResource DataGridTopLeftColumnHeader}" /><DataGridColumnHeadersPresenter Name="PART_ColumnHeadersPresenter"="1"="0" ="2" /><Rectangle Name="PART_ColumnHeadersAndRowsSeparator"   ="0" ="3" ="0"   VerticalAlignment="Bottom"   Height="1"   Fill="{DynamicResource DataGridGridLinesBrush}" /><DataGridRowsPresenter Name="PART_RowsPresenter"   ="1"   ="2"   ="3" ="0"><><ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True" /></></DataGridRowsPresenter><Rectangle Name="PART_BottomRightCorner"   Fill="{DynamicResource DataGridScrollBarsSeparatorBackground}"   ="2"   ="2" /><Image Source="/Assets/"   ="1" ="2" ="0" ="4"   VerticalAlignment="Stretch"   HorizontalAlignment="Right"   Width="60"   Stretch="Fill"   IsHitTestVisible="False"   ZIndex="1" /><ScrollBar Name="PART_VerticalScrollbar"   Orientation="Vertical"   ="2"   ="1"   Width="{DynamicResource ScrollBarSize}"   ZIndex="2" /><Grid ="1"  ="2"  ColumnDefinitions="Auto,*"><Rectangle Name="PART_FrozenColumnScrollBarSpacer" /><ScrollBar Name="PART_HorizontalScrollbar"   ="1"   Orientation="Horizontal"   Height="{DynamicResource ScrollBarSize}" /></Grid><Border Name="PART_DisabledVisualElement"="3" ="0"="0" ="4"IsHitTestVisible="False"HorizontalAlignment="Stretch"VerticalAlignment="Stretch"CornerRadius="2"Background="{DynamicResource DataGridDisabledVisualElementBackground}"IsVisible="{Binding !$parent[DataGrid].IsEnabled}" /></Grid></Border></ControlTemplate>

数据模板

<DataTemplate>    <TextBlock Text="{Binding Title}" /></DataTemplate>

风格

设计外观和行为动作

设置器

Setter 类的Property属性用来指明你想为目标的哪个属性赋值,Value属性则是你提供的属性值

<Style Selector="Grid Button">    <Setter Property="BorderBrush" Value="rgb(94, 95, 109)" />    <Setter Property="BorderThickness" Value="1" />    <Setter Property="FontSize" Value="16" />    <Setter Property="Padding" Value="10,0,10,2" />    <Setter Property="Height" Value="32" />    <Setter Property="CornerRadius" Value="6" />    <Setter Property="Margin" Value="0" />    <Setter Property="FontFamily" Value="avares://TmCGPTD/Assets/#Lato" />    <Setter Property="Transitions">        <Transitions>            <BrushTransition Property="Background" Duration="0:0:" />        </Transitions>    </Setter></Style>

上面的例子是针对 Grid ButtonStyle,使用了若干个Setter来设置 Grid 中的Button的一些属性,这样,在程序中, Grid 中的Button就会具有统一的风格。

触发器

当条件满足时会触发一个行为。

<Grid>    <TextBlock Text="raokun" Width="75" Height="20">        <>            <Style TargetType="TextBlock">                <>                    <Trigger Property="IsMouseOver" Value="True">                        <Setter Property="Foreground" Value="blue" />                    </Trigger>                </>            </Style>        </>    </TextBlock></Grid>

上面的例子,是当鼠标移动在上面时,字体的颜色变成蓝色。

阅读如遇样式问题,请前往个人博客浏览: 

拥抱ChatGPT:

开源项目地址:/firstsaofan/TerraMours

关键词: