WPF的前世今生
1、WPF的布局
WPF的布局分为相对定位和绝对定位两种。
绝对定位一般用Canvas
相对定位一般用Grid、StackPanel、DockPanel、WrapPanel
2、MVVM模式是什么
MVVM就是Model View ViewModel
Model层就是数据层,你可以把它理解成实体层,一般情况下,只要不和服务端挂钩或者小型项目,写一个实体类就行了,和服务端挂钩,或者大型项目加入了DTO,小项目返回原生对象就行了,它此时是有状态的,要和数据库挂钩,比如你用到SqlSugar,你这个实体类就不能单独的继承BindableBase了
View就是视图,你写的Xaml文件用来展示前端界面的,还有就是你对绑定、事件的声明
ViewModel层就是业务处理的,用来处理你前面View的所有声明,通常也会监听View层,比如ViewModel层更新,View层更新
优点就是降低代码耦合,提高重用性
3、Xaml文件
一般情况下,你可以使用Xaml文件来写WPF的前端页面(但是不一定,后文提到)
Xaml文件,你可以理解为Xml文件的扩展,
通常,我们Xml文件是这样书写的
<object>
<Animal>
<Cat></Cat>
</Animal>
</object>
在Xaml文件中格式也是一样的。
<Window
x:Class="WPFSample.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:WPFSample.Controls"
xmlns:views="clr-namespace:WPFSample.Views"
Title="How to create a WPF"
Width="500"
Height="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</Window>
在我们普通的书写代码中,不管是java还是C#,或者是Python,
他们的.cs、.java 、.py文件上方是
using xxx;
import xxx;
这个using和import就在Xaml文件中使用xmlns表示。
我在写详细一点
你的MainViewModel要应用一个Student类
那么你可以这样书写
using WPFSample;
using WPFSample.Student;
public class MainViewModel
{
private Student Stus{get;set;}
}
那么在Xaml文件中你可以这样做
<Window x:class="WPFSample"
xmlns:stu="WPFSample.Student">
</Window>
stu是随便取得名字,方便在下面使用
现在我们来编写一个简单的页面
如果你了解Html或者一点Vue,那么你就能更好的理解了,不了解没关系,我可以详细的为你解答
1、你首先使用VS创建一个WPF的程序,并且你运行了它,它打开后是一个弹窗,差不多和一个QQ的登录界面一样大小。
2、你可以写一个Button控件,并且描述了它的长宽,以及它的内容
<Button Width="200" Height="25" Content="按钮"/>
3、运行代码,你可以发现,弹窗中有了按钮
4、现在你想复刻QQ的界面
你这样写了
<TextBlick Text="登录"/>
<TextBox Width="200"/>
<Button Width="80"/>
你发现错落有致,没有达到你想要的效果
那么,就要用到WPF的布局了
<Grid Margin="100,50,100,50">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="30"
Text="{Binding appData.SystemName}" />
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock
Width="60"
Margin="50,0,0,0"
VerticalAlignment="Center"
FontSize="18"
Text="用户名:" />
<TextBox
Width="200"
Margin="10,0,0,0"
VerticalAlignment="Center"
mah:TextBoxHelper.Watermark="请输入用户名"
mah:TextBoxHelper.ClearTextButton="True"
Text="{Binding appData.CurrentUser.Name}" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock
Width="60"
Margin="50,0,0,0"
VerticalAlignment="Center"
FontSize="18"
Text="密码:" />
<PasswordBox
Width="200"
Margin="10,0,0,0"
VerticalAlignment="Center"
mah:TextBoxHelper.ClearTextButton="True"
mah:TextBoxHelper.Watermark="请输入密码"
converter:PasswordBoxHelper.Attach="True"
converter:PasswordBoxHelper.Password="{Binding appData.CurrentUser.Password,Mode=TwoWay}" />
<!--<TextBox
Width="200"
Margin="10,0,0,0"
VerticalAlignment="Center"
Text="{Binding appData.CurrentUser.Password}" />-->
</StackPanel>
<StackPanel
Grid.Row="3"
Margin="40,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<Button
Width="80"
Command="{Binding LoginCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=mah:MetroWindow}}"
Content="登录"
IsDefault="True" />
<Button
Width="80"
Margin="40,0,0,0"
Command="{Binding CancelCommand}"
Content="取消"
IsCancel="True" />
</StackPanel>
</Grid>
我现在讲解一下,这段简单的代码,你把Grid当作一个框,一间房,
你知道Row是英文行、排的意思,那么
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
这段代码就是把你刚才打开的弹窗分成了4层
程序中是从0开始的,不是1,
所以你的第一行写了TextBlock。
WPF的DataContext也是一个很重要的概念,数据上下文
默认情况下是null,在MVVM模式下,你将Model中的数据使用数据管理器或者DataService在ViewModel操作数据,写简单的业务逻辑,借此将DataContext数据上下文绑定到VM,
前端的内部也可以重新设立DataContext,举个例子
WPF中形似css+js的结合体Style,
控件中的设置值>MainWindow.Style的值>App.xaml中的值,这是优先级的划分
那么对于DataContext也是有优先级的,
通常我们使用Prism框架或者其他框架,不需要手动绑定DataContext,
他们是约定大于配置
所以在Prism中有
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
假如你在界面对StackPanel重新设置DataContext,那么这个界面除了这个StackPanel之外,其他的DataContext是从VM获取的
消息队列: Windows操作系统为每个应用程序维护一个消息队列。当用户与应用程序交互时,系统会将消息发送到这个消息队列。
消息处理: 消息循环负责从消息队列中取出消息,并将其传递给相应的窗口过程(Window Procedure)或事件处理器进行处理。
持续运行: 消息循环是一个持续运行的过程,只要应用程序还在运行,消息循环就会一直进行。
事件驱动: WPF应用程序是事件驱动的,这意味着应用程序的很多行为都是由事件(如按钮点击、文本输入等)触发的。
非阻塞: 消息循环是非阻塞的,这意味着应用程序可以在等待用户输入的同时,执行其他任务(如后台数据处理)。
窗口管理: 消息循环还负责管理窗口的生命周期,包括窗口的创建、显示、隐藏和销毁。
在WPF中,当您调用 Application.Run(new MainWindow()) 时,WPF框架会启动一个消息循环,等待和处理 MainWindow 窗口相关的消息和事件。当 MainWindow 窗口关闭时,消息循环结束,应用程序也随之关闭。
简而言之,启动应用程序的消息循环就是让应用程序准备好接收和响应用户输入和系统事件,这是应用程序能够与用户进行交互的基础。