此入门教程是记录下方参考资料视频的学习过程
开发工具:Visual Studio 2019
其实也不能算是入门教程,毕竟 WPF 已经出来很久了,教程多的很,我看的教程还挺旧的,就当是我的一个备忘录吧
随便创建一个 WPF 项目
App.xaml 的 Application 标签中的 StartUri="MainWindow.xaml"
,就是把 MainWindow 当作主窗体
xaml 是一种声明性语言,xaml 编译器会为每个标签声明一个对应标签的对象
标签分为开始标签和结束标签,开始标签里可以写一些属性 Attribute
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
http://schemas.microsoft.com/winfx/2006/xaml/presentation
:不是网址,是一个硬编码的字符串,告诉 xaml 编译器,就把这一系列类库引入到当前的 xaml 文件里xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
名称:标签
或 名称:属性
方式使用x:Class
:就是这个类的命名空间,用于指示 xaml 文件与哪个 C# 编译的类合并到一起MainWindow 这个类是 partial 声明的,所以它可以出现在多个地方,MainWindow.xaml 和 MainWindow.xaml.cs 编译完会合并到一起
InitializeComponent()
就是由 xaml 生成的
启动时的窗口是由 App.xaml 的 StartupUri 属性决定的,指向的是 xaml 文件,不是命名空间
可以使用反编译工具查看
传统方法绘制 UI 和 WinForm 是平面布局的界面,没有包含
WPF 是树形结构,可以嵌套,可以在 Blend for Visual Studio 中打开项目查看
比如这么一个界面,代码会在之后的随笔里给出
三种方式:
Human 类,在 MainWindow 中
public class Human
{
public string Name {get;set;}
public Human Child {get;set;}
}
注册命名空间,当前程序集的命名空间一般使用 local
xmlns:local="clr-namespace:命名空间"
在 Window.Resources
标签中声明 Human 对象
<Window.Resources>
<local:Human x:Key="human" Name="ZhangSan">
</Window.Resources>
每一个 WPF 程序以一个资源字典的形式维护一系列资源, x:Key="human"
就是一个键
检索资源
Human h = this.FindResource("human") as Human;
if(null != h)
{
MessageBox.Show(h.Name);
}
如何智能的转化类型?
将 Child 的值转化为对象
<Window.Resources>
<local:Human x:Key="human" Name="ZhangSan" Child="LiSi">
</Window.Resources>
添加一个 TypeConverter 类
public class NameToHumanTypeConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
string name = value.ToString();
Human child = new Human();
child.Name = name;
return child;
}
}
ConvertFrom()
中的 value 参数就是在 xaml 中使用 Attribute = "value" 这种形式赋值的时候我们得到的 value
[TypeConverterAttribute(typeof(NameToHumanTypeConverter))]
public class Human
{
public string Name {get;set;}
public Human Child {get;set;}
}
缺点:
<Button Width="120" Height="30" />
使用 />
结尾,是一个空标签,就是说这个标签不具有内容
在开始标签和结束标签之间的就是 内容 Content ,是标签的内容
<Button Width="120" Height="30" >
<!--Content-->
<Button.Content>
<Rectangle Width="20" Height="20" Stroke="DarkGreen" Fill="LawnGreen" />
</Button.Content>
</Button>
效果
属性标签就是 类名.属性
,Button.Content
中的 Button 不能省略,否则 xaml 编译器会认为你想要声明一个对象
可以使用复杂对象,弥补了 Attribute = Value
的缺点
画一个单一颜色的矩形框
<Rectangle Width="200" Height="200" Stroke="Blue" Fill="LightBlue" />
效果
若想画一个渐变颜色的矩形框,就需要使用复杂对象
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0" Y="0" />
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1" Y="1" />
</LinearGradientBrush.EndPoint>
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.2" Color="LightBlue" />
<GradientStop Offset="0.7" Color="DarkBlue" />
<GradientStop Offset="1.0" Color="Blue" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
效果
缺点:
建议:
优化之后的代码
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.2" Color="LightBlue" />
<GradientStop Offset="0.7" Color="DarkBlue" />
<GradientStop Offset="1.0" Color="Blue" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
标签扩展与 Attribute = Value 非常类似,使用 {}
例子,添加命名空间 xmlns:sys="clr-namespace:System;assembly=mscorlib"
<Window.Resources>
<sys:String x:Key="stringHello">Hello WPF!</sys:String>
</Window.Resources>
<Grid>
<TextBlock Height="24" Width="120" Background="LightBlue" Text="{StaticResource ResourceKey=stringHello}"/>
</Grid>
ResourceKey 可以省略,直接使用 stringHello ,构造函数的参数可以不写,但是一定要按顺序,为了保证代码的可读性,写出来比较好
因为标签扩展已经使用了双引号把括号引起来了,所以不需要再把里面是属性加双引号,属性之间使用括号分开
一个 TextBox 显示 Slider 的位置
<Grid Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="4"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<TextBox x:Name="tb" Text="{Binding ElementName=sld,Path=Value}"/>
<Slider x:Name="sld" Grid.Row="2" Value="50" Maximum="100" Minimum="0"/>
</Grid>
<Grid>
<Button x:Name="button1" Width="200" Height="200" Content="Click Me" Click="button1_Click"/>
</Grid>
Click 就是一个事件,Click="button1_Click"
就是事件订阅
可以手写事件处理器,也可以自动生成
自动创建的事件会以 事件拥有者 + 事件 ,中间以 下划线 隔开命名,
public MainWindow()
{
InitializeComponent();
//两种方法绑定事件
//方法一
this.button1.Click += this.button1_Click;
//方法二
this.button1.Click += new RoutedEventHandler(this.button1_Click);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
}
模块化引用 WPF 窗口
使用 User Control Library
新建一个 空白解决方案
新建一个 WPF 项目和一个 User Control Library 项目
User Control Library 项目的命名为 ControlLibrary
User Control Library 项目删除自带的 xaml 文件,新建一个 User Control,命名 SalaryCalculator
SalaryCalculator.xaml 代码
<UserControl x:Class="ControlLibrary.SalaryCalculator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ControlLibrary"
Width="240" Height="160" Background="LightBlue">
<Canvas>
<Label Name="label1" Content="基本工资" Canvas.Left="12" Canvas.Top="12" Height="28"/>
<Label Name="label2" Content="岗位工资" Canvas.Left="12" Canvas.Top="46" Height="28"/>
<Label Name="label3" Content="实际工资" Canvas.Left="12" Canvas.Top="80" Height="28"/>
<TextBox Name="textBox1" Canvas.Left="88" Canvas.Top="14" Height="23" Width="140"/>
<TextBox Name="textBox2" Canvas.Left="88" Canvas.Top="48" Height="23" Width="140"/>
<TextBox Name="textBox3" Canvas.Left="88" Canvas.Top="82" Height="23" Width="140"/>
<Button Name="button1" Content="计算" Canvas.Left="88" Canvas.Top="125" Height="23" Width="140" Click="button1_Click"/>
</Canvas>
</UserControl>
事件函数,写的随便一些,结果不是这次不是重点
private void button1_Click(object sender, RoutedEventArgs e)
{
this.textBox3.Text = this.textBox1.Text + this.textBox2.Text;
}
编译一下
WPF 项目
右键依赖项,选择添加项目引用,这样在 xaml 中写命名空间就有智能提示了
xmlns:controls="clr-namespace:ControlLibrary;assembly=ControlLibrary"
完整的窗体代码
<Window x:Class="导入程序集和引用其中的名称空间.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:导入程序集和引用其中的名称空间"
xmlns:controls="clr-namespace:ControlLibrary;assembly=ControlLibrary"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<controls:SalaryCalculator Grid.Column="0" Grid.Row="0"/>
<controls:SalaryCalculator Grid.Column="1" Grid.Row="0"/>
<controls:SalaryCalculator Grid.Column="0" Grid.Row="1"/>
<controls:SalaryCalculator Grid.Column="1" Grid.Row="1"/>
</Grid>
</Window>
效果
Telerik 可以买控件
<!-- -->
Visual Studio 快捷键
注释:Ctrl + K Ctrl + C
解注释:Ctrl + K Ctrl + U
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
是对 x 名称空间的声明
x 名称空间里的类都是用来解析和分析 xaml 代码的,即 x 名称空间就是 xaml 名称空间
标签扩展
Attribute
XAML 指令元素
x:Class 是用来声明类的
指示 xaml 文件所声明的这个类,最后要与哪个名称空间中的哪个类进行合并
例如 x:Class="WpfApplication1.MainWindow"
就是 WpfApplication1 名称空间下的 MainWindow 类与 xaml 合并
x:ClassModifier 指的是类的访问级别
xaml 文件中的取值必须和类的访问权限一致,否则会报错
是 x 名称空间中的 Name ,不是 Name 属性
作用
xaml 语言是一种声明性语言,每见到一个标签,就会声明一个实例,并不是创建一个变量(实例可以独立存在,变量引用实例)
建议使用 x:Name 而不使用 Name ,因为没有继承 FrameworkElement 的类可能没有 Name ,只能使用 x:Name
控制类中字段的访问级别,但是是给标签用的
在 User Control Library 中使用可以防止被外部修改,增强安全性
原文:https://www.cnblogs.com/zzy-tongzhi-cnblog/p/14805882.html