Article directory
related resources
"Introduction to WPF in Simple" series of high-definition video tutorials | Lecturer: Liu Tiemeng
Download the full version of wpf pdf version in simple terms,
Mr. Liu Tiemeng's B station number. but only recent video material
foreword
WPF is a very advanced technical framework, even though it was developed in 2007 and officially released in 2010. The MVVM inside, the business code and the interface code are completely separated, and the idea of low coupling and high cohesion has always affected the later front-end development. For example, Vue is inherited from MVVM.
The situation of WPF in the domestic job market is not ideal. The reason is that the desktop software has declined, and the functions have gradually shifted from the PC side to the WEB side. I can solve it with a web page, why do I need a client? The promotion of WPF technology is also a problem. Because of the rise of the traditional Internet, Java has been raised to a very high level. Java has a lot of wheels, the ecology is particularly good, and there are many people who learn it.
So I think, don't think that you can find a good job after learning WPF. .NET engineers still have to switch to the full stack, both front-end and back-end. I currently think the simplest full-stack technology stack is Vue+uniapp+WPF+webApi+.NET core. Database: Sql server sqlite Mysql. In fact, it is best to learn Unity 2d+Unity 3d +C4D. This is the complete full stack. Basically a simple small project you can solve.
My template for this year is to learn WPF+Unity 2d+C4D modeling. The logic of my learning has always been from low to high, that is, to learn how to use tools first, and then to delve into advanced things. After learning this part, I will start learning linux and python next year.
C# and JAVA are competing with each other, and I don't have the energy to learn Java for the time being. I'll talk about it when I need it
Although a bit off topic, back toEasy to understand WPF, Teacher Liu Tiemeng is still very fierce, and the explanation is very good. Unlike other classes, I will talk about the control properties for a few hours first. It starts directly from the principle, from the bottom layer to the application, which is very clear.
WPF study notes
Video data address
"Introduction to WPF in Simple" series of high-definition video tutorials | Lecturer: Liu Tiemeng
Environment configuration
- .NET Core 6.0
- WPF
WPF basics: how a WPF program is started
A simple WPF program we created.
How are xmal files and cs files connected
In order to separate pages and services, WPF forces us to only write pages in xmal and write services in cs files. This forced separation is to reduce coupling. If some students have tried to maintain the JQuery project, they will know how painful it is that the business and the page are not separated. A function contains page logic and business logic, so when making changes in the later stage, you must fully understand how the entire function works, and if you delete a variable at will, you will report an error directly.
Let's take App.xmal and App.xaml.cs as an example
How to determine the splash page
How does an xmal file refer to other files
how to cite
How WPF creates elements and changes elements
WPF performs a high degree of page and business segmentation, and then maps the corresponding pages and files through compilation. All our element creation and simple interaction events happen in xmal.
WPF element creation and simple attribute assignment
Take a simple button as an example
Create controls in layout elements.
<Grid>
<Button Content="Show Msg!"//显示的文字
Click="Button_Click"//点击事件
Width="100"//宽度
Height="30" />//高度
</Grid>
What is wrapped by <> is a label, and the <> is followed by an attribute. In the above example, Button is the label, and Grid is also the label. Content, Click, Width, and Height are all attributes.
achieve effect
WPF tree interface
WPF's xmal is very similar to html, both are markup languages
This tree hierarchy is the hierarchy of WPF.
If you want to know more about it, you can read my previous article.
How WPF Views Page Elements in Real Time How to Use the Real-time Visual Tree
Xmal attribute assignment
There are three methods of attribute assignment in Xmal.
- Inline label: the default assignment method
- Property Label: String Input Conversion Data Type
- extension tab
Why multiple attribute assignments
Let's look at the simplest Button button
<Grid>
<Button Content="Show Msg!"//字符串标签
Click="Button_Click"
Width="100"//属性标签
Height="30" />
</Grid>
We can see that the values we assign are all strings. Like Content, it must be a string, but Width and Height, the attribute value should be a number, but what we input is also a string. Just to clarify: we can convert the copied string.
attribute conversion
The purpose of attribute conversion is for us to generate some complex information through tag attributes. For example, Height = "100". Height assigns a string, which must be converted into a number.
We create a new Person class
MainWindow.cs
namespace WpfLearnTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)//按钮事件
{
///找到资源字典中名字为person的类
Person _model = (Person)this.FindResource("person");
MessageBox.Show(_model.Name);
}
}
public class Person
{
public string Name {
get; set; }
public Person Chil {
get; set; }
}
}
MainWindow.xmal
<Window x:Class="WpfLearnTest.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:WpfLearnTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:Person x:Key="person" Name="小王" />//声明Person类
</Window.Resources>
<Grid>
<Button Content="Show Msg!"
Click="Button_Click"//添加点击按钮
Width="100"
Height="30" />
</Grid>
</Window>
achieve results
The reason it works is because the Name of our Person class is a string, but what if it's not a string?
We can see that Child reports an error. Strings cannot be directly transferred to the Person class.
Solution
///引入属性转换
[TypeConverterAttribute(typeof(NameToPersonTypeConverter))]
public class Person
{
public string Name {
get; set; }
public Person Child {
get; set; }
}
/// <summary>
/// 添加属性转换
/// </summary>
public class NameToPersonTypeConverter : TypeConverter
{
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
string name = value.ToString();
Person child = new Person();
child.Name = name;
return child;
}
}
Effect:
The operation result is successful!
property label
issues that need resolving.
On the web page, how is it implemented in Html+css?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>一个简单的网页</title>
</head>
<body>
<div>
<button style="width: 100px;height: 30px;">
<div style="height: 10px;min-width: 10px;border: 1px solid red;display: inline-block;"></div>
</button>
</div>
</body>
</html>
Nesting can also be used in xmal
<Window x:Class="WpfLearnTest.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:WpfLearnTest"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Button
Width="100"
Height="30">
<Rectangle Width="20"
Height="20"
Stroke="DarkGreen"
Fill="LawnGreen" />
</Button>
</Grid>
</Window>
But xmal supports us to useproperty labelfill in
<Button Click="Button_Click"
Width="100"
Height="30">
<Button.Content>//属性标签,对应button的content值
<Rectangle Width="20"
Height="20"
Stroke="DarkGreen"
Fill="LawnGreen" />
</Button.Content>
</Button>
The effect achieved is the same
So what is the use of nesting an attribute tag?
The conclusion is that there is no difference in this case.
In the real-time visual tree there is no difference
Advantages and Disadvantages of Attribute Tags
We now have a need
<Rectangle Width="200"
Height="160"
Stroke="Blue"
Fill="LightBlue" />
Let's see how html+css solves it.
The web page is separated with html+css+JS. Only let html declare elements and let css modify styles. In principle, JS does not add or delete html elements during use (although DOM operations can be implemented, but this will increase coupling and easily form shit mountain codes), but through css display: none. To display or not display the page style.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>一个简单的网页</title>
</head>
<body>
<div id="box">
</div>
</body>
</html>
<style type="text/css">
#box {
height: 200px;
background-color: red;
background-image: linear-gradient(to bottom right, red, blue);
}
</style>
achieve effect
Disadvantages of attribute tags
Let's see how to write WPF to achieve the above effect?
<Rectangle Width="200"
Height="160"
Stroke="Blue">
<Rectangle.Fill>
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0"
Y="0" />
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1"
Y="1" />
</LinearGradientBrush.EndPoint>
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.2"
Color="LightBlue" />
<GradientStop Offset="0.7"
Color="DarkBlue" />
<GradientStop Offset="1.0"
Color="LightBlue" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
We can see that it is just a simple gradient effect, so it is very troublesome to write
Of course, we can use inline tags to optimize
<Rectangle Width="200"
Height="160"
Stroke="Blue">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">//使用行内标签来对代码进行优化
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.2"
Color="LightBlue" />
<GradientStop Offset="0.7"
Color="DarkBlue" />
<GradientStop Offset="1.0"
Color="LightBlue" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
We can use resource dictionaries to optimize
<Window.Resources>
<Style x:Key="MyButton"
TargetType="Button">
<Style.Setters>
<Setter Property="Content"
Value="" />
</Style.Setters>
</Style>
<Style x:Key="MyRectFill" TargetType="Rectangle">
<Style.Setters>
<Setter Property="Fill" >
<Setter.Value>
<LinearGradientBrush StartPoint="0,0"
EndPoint="1,1">
<GradientStop Offset="0.2"
Color="LightBlue" />
<GradientStop Offset="0.7"
Color="DarkBlue" />
<GradientStop Offset="1.0"
Color="LightBlue" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Window.Resources>
<Grid>
<Rectangle Width="200"
Height="160"
Stroke="Blue" Style="{
StaticResource MyRectFill}" >
</Rectangle>
</Grid>
We ensure the simplification of page elements, but due to the operation of WPF, Window.Resources can only be placed before page elements. And since C# and Xmal are strongly defined languages, it is necessary to declare the element content when writing.
What can be solved by 5 lines in CSS can be solved by 10 lines in Xmal.
extension tab
In the code we just wrote
<Rectangle Width="200"
Height="160"
Stroke="Blue" Style="{
StaticResource MyRectFill}" >//这个就是扩展标签
</Rectangle>
The extension tag uses the form of {} to include the attribute value in it. At this time, what we input is not a string, but an attribute object. If students have learnedVueYou can see that this is similar toVueThe difference expression { {value}}.
Tag extensions generally work with attribute binding, and I will explain how to use attribute binding later. This is the focus of WPF.
WPF Property Binding
Assignment of page elements to each other
I said earlier that content relationships in WPF are as follows
In xmal, elements can be communicated, but not on the Web side. The Web needs to modify data through JS event triggers. This is event-driven. The event-driven type believes that all page interactions are triggered by events, and the communication between two page elements must have an intermediate event.
In Xmal, it is data-driven, or it can be regarded as an anonymous event. That is, I don't need to declare an event, I just give him the value directly
xmal code
<Grid>
<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>
WPF data binding will be described in detail later in the Prism framework.
WPF componentization
Componentization means encapsulating a reusable interface into a component. There are 4 classes in WPF
- window: a window. Windows cannot be nested
- Page: It is rarely used, and I don’t know what it does, it seems to be a web page.
- User Control: Set on top of the window. for abstracting components
- Resource dictionary: used to manage WPF resources, such as styles and controls.
We create a new WPF resource class
New Project
Then add the following code
UserControl1.xmal
<UserControl x:Class="ControlLibrary.UserControl1"
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"
mc:Ignorable="d"
d:DesignHeight="160"
d:DesignWidth="240"
Background="LightBlue">
<Canvas>
<TextBox Canvas.Left="110"
TextWrapping="Wrap"
x:Name="textBox1"
Canvas.Top="10"
Width="120"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<TextBox Canvas.Left="110"
TextWrapping="Wrap"
x:Name="textBox3"
Canvas.Top="105"
Width="120"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<TextBox Canvas.Left="110"
TextWrapping="Wrap"
x:Name="textBox2"
Canvas.Top="63"
Width="120"
HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock TextWrapping="Wrap"
Canvas.Top="10"
Canvas.Left="10"><Run Language="zh-cn"
Text="num1" /></TextBlock>
<TextBlock TextWrapping="Wrap"
Canvas.Top="63"
Canvas.Left="10"
HorizontalAlignment="Center"
VerticalAlignment="Top"><Run Text="num" /><Run Language="zh-cn"
Text="2" /></TextBlock>
<TextBlock TextWrapping="Wrap"
Canvas.Top="107"
Canvas.Left="10"
HorizontalAlignment="Center"
VerticalAlignment="Top"><Run Language="zh-cn"
Text="总计" /></TextBlock>
<Button Content="计算"
Canvas.Left="126"
Canvas.Top="136"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Width="88"
Click="Button_Click" />
</Canvas>
</UserControl>
UserControl.xmal.cs
using System;
......
namespace ControlLibrary
{
/// <summary>
/// UserControl1.xaml 的交互逻辑
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.textBox3.Text = ( int.Parse(this.textBox1.Text) + int.Parse(this.textBox2.Text) ).ToString();
}
}
}
and then add a reference to it
Regenerate every project
referenced in the main function
<Window x:Class="WpfLearnTest.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:WpfLearnTest"
xmlns:sys="clr-namespace:System.Security.Claims;assembly=mscorlib"
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:UserControl1 Grid.Row="0"
Grid.Column="0" />
<controls:UserControl1 Grid.Row="1"
Grid.Column="1" />
<controls:UserControl1 Grid.Row="1"
Grid.Column="0" />
<controls:UserControl1 Grid.Row="0"
Grid.Column="1" />
</Grid>
</Window>
use result
It can be imported directly, and the code of the user control can be executed (the total result is num1+num2).