深入浅出wpf学习总结
一、创建项目
注意:项目创建时系统会为你生成和项目名称同名的命名空间,看起来没有什么问题,但当你的项目是以数字开头这是允许的,命名空间是标识符(包含:字母(A-Z, a-z)、数字(0-9)和下划线_),不能以数字开头,IDE会帮你补充一个下划线_,会出现你的命名空间和项目名称不一致,在使用用户控件时,自己写xaml代码中的xmlns时容易出现错误!
二、项目结构

层次一:解决方案
层次二(解决方案下)
项目(一般三种:类库、windows应用程序、控制台应用程序),项目说编译出来的叫程序集(Assembly)
层次三(项目下):源代码
properties:资源文件的描述
References:引用的类库(双击可以打开对象浏览器,可以看到类库中的属性和方法)
App.xaml:对应应用程序本身
<Application x:Class="_2025_10_29_ltm.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:_2025_10_29_ltm"StartupUri="MainWindow.xaml">//设置启动页面(主窗体)<Application.Resources></Application.Resources>
</Application>MainWindow:主窗体
<Window x:Class="_2025_10_29_ltm.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:_2025_10_29_ltm"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid></Grid>
</Window>前置知识:
- xmlns:是一个特征和Title这些其他特征没有区别,xml的namespace,xaml语言脱胎于xml
- xaml名称空间规定有一个名称空间是可以不加名字的,叫默认名称空间。
- XAML是声明式语言,每一个标签(控件)对应一个对象(控件对象),写一个标签编译器就会为你生成一个对象,可以修改他的Attribute(特征)
- xmlns:【可选映射前缀】=“名称空间”,这里的映射前缀中的前是指当使用这个名称空间下内容时这个前缀是写在前面的
逐句解析:
句一:x:Class="_2025_10_29_ltm.MainWindow"
这里x是xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"定义的映射前缀,说明class是来源于x名称空间,这句话的作用是声明:是为一个已有的C#类(MainWindow)补充声明式的UI定义
句二:xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
这种类似于网址的东西叫硬编码,作用是将一系列类库引入到xaml文件中:在c#代码中使用using来引入名称空间,一个using引用一个,这个硬编码可以映射10个或者更多名称空间,presentation后缀的名称空间主要是绘制界面相关(控件布局相关),这也就解释了为什么要把这个硬编码设置为xaml中的默认名称空间:如果不设置这个为默认需要在使用控件的时候加上前缀非常繁琐。下面代码展示不使用默认名称空间
<s:Window x:Class="_2025_10_29_ltm.MainWindow"xmlns:s="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:_2025_10_29_ltm"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><s:Grid></s:Grid>
</s:Window>句三:xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
后缀为xaml是xaml文件的编译解析相关,:x中x是映射,即x就对应"http://schemas.microsoft.com/winfx/2006/xaml"
句四:xmlns:local="clr-namespace:_2025_10_29_ltm"
当使用用户控件时,这个控件在这个命名空间(项目的命名空间)中查找
clr-namespace::这是固定的关键字,指明后面跟的是.NET代码中的命名空间。
命名空间名称:就是你C#代码中namespace关键字后面的名称,例如_2025_10_29_ltm。
assembly=程序集名称:这个部分是可选的。当要引用的类位于当前项目之外的其他程序集(.dll文件)时,才需要指定。如果类就在当前项目里,可以省略assembly部分,编译器会自动在当前程序集中查找当要引用的类是在当前项目下时,
clr-namespace:也可以省
深入探讨:xaml和xaml.cs关系
关键在于理解XAML文件在编译过程中扮演的双重角色:它既是被加载的资源,也是用于生成类定义的蓝图。
关系2.1. 详解XAML的双重角色与合并机制
编译过程是解开谜团的关键。MainWindow.xaml文件在编译时会被处理两次,产生两种不同的输出,最终在运行时合一。
XAML作为“蓝图”生成C#代码(.g.cs文件)
当编译器看到XAML根元素上的
x:Class="MyApp.MainWindow"属性时,它就明白这个XAML文件的目的是为一个已有的C#类(MainWindow)补充声明式的UI定义于是,编译器会自动生成一个名为
MainWindow.g.cs的分部类(partial class)文件。这个文件里主要包含:为所有在XAML中使用了
x:Name的控件生成的字段声明(如internal Button SubmitButton;)。核心的
InitializeComponent()方法。
手写的
这就是“合并为一个类”的真正含义。MainWindow.xaml.cs文件是同一个MainWindow类的另一个部分。编译时,编译器会将自动生成的MainWindow.g.cs和您手写的MainWindow.xaml.cs合并成一个完整的MainWindow类定义
XAML作为“数据”生成BAML资源
与此同时,XAML文件本身的内容(那些标签和属性)会被编译成一种高效的、二进制的BAML(Binary Application Markup Language)格式
这个BAML文件会被作为资源嵌入到最终生成的程序集(.exe或.dll)中。这就是理解的“XAML文件是作为资源”的部分。
关系2.2 xaml上的控件(标签)本质也都是对象
在xaml中我们使用标签来构成页面,但是标签本质也是类的对象,那么如果一个类定义在.cs文件中我们可以像使用用户控件一样将其作为xaml页面的内容
同理因为我们xaml和xaml.cs最后可以合并为一个类,xaml中的内容也完全可以在.cs文件中编写,方法有:从层级上、通过x:name特征直接对应两种
三、用户界面的树形结构
直接在文档大纲下查看,单击直接选中xaml代码
大纲位置:视图->其他视图->文档大纲
快捷键:ctrl+alt+T

四、在xaml中为对象属性赋值
Attribute(键对值方式):值只能为字符串
属性元素:当值是非字符串时
例如:我们需要添加在button的内容中添加一个矩形,这时无法使用键对值方式来进行(非字符串)
<Button>
<Button.Content>//属性标签<Rectangle Height="200" Width="200" Fill="Red"></Rectangle>
</Button.Content>
</Button>标签扩展
就是使用{}代替值,BaseOn=就是标签扩展
<Window.Resources><Style TargetType="Button" x:Key="ButtonStyle"><Setter Property="Background" Value="Green"/></Style>
//给基础样式命名的继承方式<Style BasedOn="{StaticResource ButtonStyle}" x:Key="ButtonStyle1" TargetType="Button"><Setter Property="Background" Value="Black"/></Style>
</Window.Resources>
<Grid ><StackPanel><Button Style="{StaticResource ButtonStyle}" Content="Click Me"></Button><Button Style="{StaticResource ButtonStyle1}" Content="Click Me"></Button></StackPanel>五、事件处理器
事件分为:事件的拥有者,事件,订阅关系,事件的响应者,事件处理器
如下:我们已经有了事件的拥有者(Button1)和事件(Click),但是点击后没有触发,这是因为没有其他事件的部分
<Button Content="Button1" Height="50" Width="100" Margin="10"/>当我们填写Click特征时可以自动生成事件处理器在后台文件中,事件的响应者是窗体(后台类),Click特征是事件的订阅者,处理器是后台文件的函数
<Button Content="Button1" Height="50" Width="100" Margin="10" Click="Button_Click"/>后台代码:
public partial class MainWindow : Window//这个类就是事件的拥有者{public MainWindow(){InitializeComponent();}//事件处理器private void Button_Click(object sender, RoutedEventArgs e){}事件的订阅关系也可以使用c#的写法
删除掉xaml中的Click特征
后台代码修改如下
public partial class MainWindow : Window{public MainWindow(){ InitializeComponent();//订阅这个按钮的Click事件this.Button1.Click += new RoutedEventHandler(Button_Click);}private void Button_Click(object sender, RoutedEventArgs e){MessageBox.Show("Hello World!");}}六、导入程序集和引用命名空间
6.1、在一个项目下用户控件的创建和使用
资源管理器,项目上右键选择新建,选择用户控件,会发现和项目在同一个名称空间下
namespace _2025_10_29_ltm
{/// <summary>/// UserControl2.xaml 的交互逻辑/// </summary>public partial class UserControl2 : UserControl{public UserControl2(){InitializeComponent();}}
}在程序生成时主页面已经会自动生成local自动前缀,直接local:控件名称来使用
<Window x:Class="_2025_10_29_ltm.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:_2025_10_29_ltm"mc:Ignorable="d"Title="MainWindow" Height="300" Width="400"><Grid><local:UserControl2></local:UserControl2></Grid></Window>6.2关于命名空间的小问题
当我们在项目下直接创建用户控件,哪怕移动用户控件到文件夹下也无需改动用户控件的名称空间,因为他会在名称空间下寻找
如果直接在文件夹上右键来创建用户控件那么就会创建一个子命名空间,当我的主窗口需要使用这个用户控件时,必须要引用这个子命名空间
主窗口页面:
<Window x:Class="_2025_10_29_ltm.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:_2025_10_29_ltm"xmlns:Components="clr-namespace:_2025_10_29_ltm.Components"mc:Ignorable="d"Title="MainWindow" Height="300" Width="400"> <Grid> <Components:UserControl3></Components:UserControl3></Grid>
</Window>用户控件:
namespace _2025_10_29_ltm.Components
{public partial class UserControl3 : UserControl{public UserControl3(){InitializeComponent();}}
}6.3、创建控件库使用库中控件
解决方案下右键创建项目,选择用户控件库
在主项目下右键引用,添加库引用
在xaml中添加这个命名空间,即可使用
七、X名称空间常用内容
x:class
作用:是最后xaml文件是作为谁的资源
使用要求:
- 只能用在xaml文件的根节点
- x:Class根节点类型必须和值类型一致(这里的根节点是Window,值也必须是Window类型)
- x:值必须是partial类型
x:ClassModifier
作用:修改最后生成类的访问级别
使用要求:
- 必须有x:class
- 必须和要合并类的访问级别设置为一致
- 可以不加默认值是public
X:Name
我之前粗浅的认为是给标签取名字,实际上看标签是一个类型的实例,X:name是一个引用变量,本质上是引用变量=实例
注意:
控件如果是framework element的子类(WPF原生控件都是)有name属性,和使用x:name等价
但如果这个控件不是framework element的子类那么就只能使用x:name,例如:使用.cs文件中的类作为标签就只能使用x:name。
x:FieldModifier
在使用了x:name后就声明了引用变量,自然涉及到访问级别,默认级别为internal,当我们需要跨程序集访问这个控件时,可以修改为public
x:Key
为资源添加索引,也可以认为给资源起了个名称,但是原理和使用对象与x:name不同
<Window.Resources><!-- 定义一个画刷资源,并为其指定键(Key)为 "MyFavoriteBlue" --><SolidColorBrush x:Key="MyFavoriteBlue" Color="#FF0066CC"/>
</Window.Resources>
<StackPanel><!-- 使用定义好的画刷资源设置按钮的背景色 --><Button Background="{StaticResource MyFavoriteBlue}" Content="第一个按钮" /><Button Background="{StaticResource MyFavoriteBlue}" Content="第二个按钮" />
</StackPanel>