Winform基础学习及项目开发

在对C#语言进行初步学习后,研究开发Winform应用程序,本文从基本概念入手进行讲解

Posted by R on 2023-03-06

前言

我有一个习惯,在学一个东西的时候总想着尽量详细的掌握和它相关的所有概念,再用简单的话来描述它。好处在于了解的确实多,感觉什么都懂一点,但是太容易忘,也太费劲了。还有一点在于,牵扯出来的东西我似乎永远无法全部掌握,总有新的名词、新的技术冒出来,像窗台上的灰尘,或是反复出现的胡子渣。我想从当前的状态里挪出去几步,尽可能深入的去了解一个领域、一项技能,多而不精很容易,专精则要难很多。这不表示着不去接收新的领域,我觉得,在真正掌握一种技术后,再去以那样的视角学习其他技术要更加得心应手。

拿现在的项目来说,要具体操手项目,起码得看懂并且修改续写项目代码,这需要对 Winform 进行系统性的学习,同时 C# 语言的进度也不能丢。由于其特性涉及到了.net 领域相关技术,这一过程中则必然的延伸到了 java script。以我目前的了解,这个领域的范围到这里基本上可以有了确定的界限,因此现阶段的目标就是跑通项目流程,把 C# 和 Winform 在已有基础上深入学习,大体掌握后再开始对 java 相关的问题进行学习。这样的规划基本程度上能让我对三大块语言都有一定的基础(我的理解是 python、java 以及 c 系列属于主流三大块),后续再针对项目过程中学习到的相关知识加以深入研究(网络协议等)。编程方面,我并没有太多基础可言,相较于计算机专业的学生还有一定的差距,因此还是需要尽快通过项目任务来缩短距离。如果再往后拓展,那么我也想去回过头学习学习硬件,尽可能多的接触一些领域,在择业的时候也能有更多想法。

这里再插一嘴,之前一直以为项目文件是采用的 wpf 实现的,知道今天学习 wpf 才发现不对劲。经过查证才知道是 winform 项目,实在是太乌龙了。Winform 和 WPF 同属应用程序设计,最大的区别在于布局方式和驱动方式:

  • 一般来说,界面布局的方式有两种,一种是拖控件,另一种是通过布局控件来实现,而 Winform 主要是以拖控件的方式为主,配合布局控件做整体布局,而 WPF 则恰恰相反,虽然也可以拖控件,但是很少这么做,主要是通过编写 XAML 代码来实现。
  • 驱动方式方面,Winform 是基于事件驱动,WPF 是基于数据驱动,以操作一个按钮,执行一个查询操作为例,Winform 是在按钮的点击事件里,写好查询代码,然后将结果展示在数据控件里,而WPF 则是通过按钮绑定一个动作方法,数据控件绑定好数据源,在方法里查询即可,这样做的目的就是尽量减少前后端的耦合。

MVVM、MVC、MVP

谈到学习 Winform 的开发,就必须要学习 MVVM ,学习 MVVM ,就要首先了解 MVC、MVP 等概念。不论是 MVP 还是 MVVM,,基础都在于 MVC。

  • MVC 的全称即 Model-View-Controller,核心是三层模型 Model-View-Control 。它是一种客户端软件开发框架,view 负责显示,model 负责提供数据,controller 则负责逻辑的处理,实现流程大概如下:

    • 当用户需要发送请求时,首先是在 View 发送请求,由 View 将指令传送到 Controller 里。
    • Controller 接收到指令之后,先完成所需要的业务逻辑,然后要求 Model 根据业务逻辑改变状态。
    • Model 将新的数据发送给 View,View 则根据新的数据更新视图,从而用户的请求得到反馈。

    在 MVC 框架中,View 是可以直接访问 Model 的,这样不可避免的使 View 里面也需要包括一些业务逻辑,同时还需要 Model 保持不变,而 Model 又对应着多个不同的显示(View),所以总体说来就是,在 MVC 模型里面,Model 不依赖 View,但是 View 是依赖于 Model 的。这样就导致更改 View 比较困难,且业务无法重用。从而 MVC 框架的弊端就显现出来,前后端没有解耦,Model与View没有彻底解耦。(解耦,字面意思就是解除耦合关系,接触两者间的相关关系。)

  • 为了解决 MVC 框架中 View 和 Model 联系紧密的问题,开发者研究开发了 MVP 模式,MVP 即 Model-View-Presenter,即把 MVC 中的 Controller 换成了 Presenter,目的就是为了完全切断 View 跟 Model 之间的联系,在 MVP 模式中,View 负责视图的显示,Model 负责提供数据,Presenter 则主要负责逻辑业务的处理。Presenter 与 View 也是没有直接相关联的,而是通过已定义的接口进行交互,从而使得在变更 View 的时候可以保持 Presenter 的不变,即保证了 Presenter 的可重用性(接口的复用性),同时也解决了 MVC 框架中的 View 和 Model 关联紧密的问题。

  • 对于大型项目而言,前端的东西原来越多,造成服务端的压力越来越大,而且由于MVP的出现,逐渐向前后端分离靠拢,分离之后,View 分担服务端的压力,或者说是浏览器分担了服务器压力,包括页面渲染,路由等问题,这时侯 MVVM 出现了。(推测说法)MVVM 框架便是前后端分离框架发展史上的一次思想的完全变革。它是将数据模型双向绑定的思想作为变革的核心,即 View 的变动,自动反映在 ViewModel 上面,而 ViewModel 的变动也会随即反映在 View 上面,从而实现数据与模型的双向绑定。

    在 MVVM 框架中,View 用于发送用户的交互请求,之后将用户请求转交给 ViewModel,ViewModel 即可根据用户请求操作 Model 数据更新,待 Model 数据更新完毕,便会通知 ViewModel 数据发生了变化,然后 ViewModel 就会即刻更新 View 数据,完成视图的更新,从而完成用户的请求。
    虽然MVVM框架和之前的 MVC、MVP 式的目的相同,即完成视图(View)和模型(Model)的分离,但它却有着明显的优势:

    • 首先,MVVM 框架中的 View 完全可以独立于 Model 发生变化和修改,彻底解耦,View 发生变化时 Model 可以不变,同样,当 Model 发生变化时 View 也可以不变化,并且一个 ViewModel可以绑定到多个不同的 View 上面,这就体现了 MVVM 框架的低耦合性。
    • 其次,绑定在一个 ViewModel 上面的多个 View 都可以使用 ViewModel 里面的视图逻辑,完成了框架可重用性的特性。除此之外,MVVM 框架还具有可独立开发、可测试等特性,把框架作用发挥到最大化,也因此成为了开发者们青睐的框架。

以上内容仅是初步介绍,很多内容并没有深入探讨,主要是我看的也似懂非懂,感觉还需要具体实操后才能更深入了解。暂且搁置,学习完成后再回过头来深入解析。

Winform基础信息

Winform 文件结构如下所示:

Winform文件结构

  1. 引用:包括所有的系统库文件的引用依赖(外部库)
  2. App.config:当前项目的配置文件
  3. Form1.cs:当前窗体的事件逻辑源码
    • Form1.Designer.cs:当前窗体的控件布局源码
    • Form1.resx:当前窗体的资源文件(图片、图标、资源等)
      !Form1.cs 和 Form1.Designer.cs 都定义了 Form1 类,该类使用了 Partial 关键词声明,其定义的类可以在多个地方被定义,最后编译的时候会被当作一个类来处理。因此两个文件各司其职,最后合并为一个类编译。
      !要手动实现自定义窗体,可以添加自己的类,然后继承 Form 类即可
  4. Program.cs:当前项目程序的主入口 Main,启动项目,运行初始窗口

窗体设计与控件布局
在设计界面拖拽控件,可以完成界面布局(控件大小、名称、类型、样式等),设计界面自动关联 Form1.Designer.cs 文件,在 InitializeComponent() 方法中会自动生成相关代码
设计原则:

- Form1.Designer.cs 文件:窗体控件布局文件,一般**不需要修改**,只要通过设计界面代码就会自动生成。
- Form1.cs 文件:窗体事件逻辑代码的实现,一般**需要手动书写**,包括触发事件、回调、数据交互、跳转等等

手动添加控件,不通过设计界面,有两种方式:

  1. 在 orm1.Designer.cs 中添加:
1
2
3
4
5
6
7
8
9
private System.Windows.Forms.Button btn_design;//声明控件
//默认的控件初始化方法
InitializeComponent():{
this.btn_design = new System.Windows.Forms.Button();//定义控件
this.btn_design.Text = "自定义控件";//设置Text属性
this.btn_design.Location = new Point(40,40);//设置布局位置 Point(x,y)
this.btn_design.Size = new Size(100,40);//设置尺寸大小 Size(width,height)
this.Controls.Add(this.btn_design);//注册控件到窗体
}
  1. 在 Form1.cs 中添加:
1
2
3
4
5
6
7
8
9
10
private Button btn_design;//声明控件
public Form1(){
//先调用Designer.cs中的控件初始化方法
InitializeComponent();
this.btn_design = new System.Windows.Forms.Button();//定义控件
this.btn_design.Text = "自定义控件";//设置Text属性
this.btn_design.Location = new Point(40,40);//设置布局位置 Point(x,y)
this.btn_design.Size = new Size(100,40);//设置尺寸大小 Size(width,height)
this.Controls.Add(this.btn_design);//注册控件到窗体
}
  1. 注意点

    一般情况都使用拖拽添加控件,当然也有特殊情况需要手动添加(比如自定义控件)。
    窗体 GUI 中,左上角为原点(0,0),竖直向下为y轴,水平向右为x轴(宽度表示 x 轴上长度,高度表示 y 轴上长度),单位为像素。

窗口设计
WinForm 自动添加事件处理:
(1)操作:在设计界面-控件属性-闪电符号(事件)-添加事件,就会在 Form1.cs 中自动生成该控件相应方法名称的事件触发函数
(2)MessageBox.Show():显示弹出消息提示框
(3)GUI 界面下 Console.WriteLine 不显示,需要使用调试模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace WindowsFormsApp_learning
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Button的Click点击事件(自动添加)
private void showMessage(object sender, EventArgs e)
{
MessageBox.Show("Hello World!");
}
}
}

WinForm 手动添加事件处理:
(1)添加按钮控件到布局
(2)书写事件处理函数,必须符合 void function_name(object param1,EventArgs e){} 的形式
(3)添加注册事件,this.Btn_design.Click += new EventHandler(this.showTip)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace WindowsFormsApp_learning
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//2.1 注册Click事件为手动添加的函数
this.Btn_design.Click += new EventHandler(this.showTip);
}

//2.Button的Click点击事件(手动添加)
public void showTip(Object sender,EventArgs e)
{
MessageBox.Show("手动添加!");
}
}
}

一般情况下自动添加事件就好,除非有自定义等情况。自动添加时注意控件在 vs 左面的工具箱中,拖动控件到 ui 界面后,点击对应控件后在右下角便有控件事件,通过控件事件即可定义功能。控件事件及属性如下图所示:
控件属性