详细讲解基于.NET的WinForm桌面应用程序的运行过程和代码原理-C# 7
本博客详细讲解基于.NET的WinForm桌面应用程序的运行过程和原理。
所用的语言是C#。
WinForm 的桌面程序在执行过程中与普通的控制台应用程序相同而又不同。
本文以一个例程,讲解WinForm 的详细过程,有助于各位加深了解WinForm。
具体而言,VS 把Winform 封装的很好,我们接下来一步步讲解。
首先我把这个例程及程序运行的界面给大家展示出来。
///Program.cs 片段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
//Form1.Designer.cs 片段
namespace WindowsFormsApp1
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.button1 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pictureBox1.Location = new System.Drawing.Point(201, 51);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(410, 253);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// button1
//
this.button1.Location = new System.Drawing.Point(338, 349);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(149, 46);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button1);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button button1;
}
}
//Form1.cs 片段
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Image = Image.FromFile("C:\\C#\\Test_WinForm\\3_PictureBox_Test\\bin\\Debug\\4.jpg");
}
}
}
桌面程序和控制台程序相同有一个入口程序,及Program.cs
我们可以看到在Program.cs中有:
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
其中Application是一个密封类,你可以看到他的定义为:
public sealed class Application { }
Application下面的属性和方法全部都是静态的。
然后程序开始执行下面两句,这是程序的预处理,自动开辟一个线程,运行窗体有关。
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
紧接着我们可以看到,程序开始执行下面这句:
Application.Run(new Form1());
这里在内存的堆中新建立了一个匿名的Form1对象。
然后程序跳转到Form1类,此类继承了System.Windows.Forms.Form基类,
我们在Form1上所添加的任何控件和事件都是重写System.Windows.Forms.Form基类的属性和方法。
程序这里跳转到:
//Form1.Designer.cs
//即:
private System.ComponentModel.IContainer components = null;
首先执行上面这句,以提供窗体必须的容器,我们可以看到,我们基本上是看不到Form1.Designer.cs这个片段的,因为VS 把它封装的很好,
至于我们接下来要看到的Form1.cs ,只是Form1.Designer.cs的一个片段而已。这是因为Form1.cs 有一个关键字partial,这是部分类的关键字,VS很巧妙的将项目内部运行的Form1.Designer.cs 和可以让开发者DIY 的Form1.cs通过partial 分割开来,一个对内封闭,一个对外公开。而且一旦你修改Form1.Designer.cs的代码,程序就会崩溃,这正是这个设计巧妙的地方。
顺其自然,自然而然执行Form1的构造方法,
//Form1.cs
public Form1()
{
InitializeComponent();
}
我们可以看到 InitializeComponent() 是初始化容器的内部成员方法。紧接着,程序跳转到内部片段Form1.Designer.cs执行Form1类的私有方法InitializeComponent()
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.button1 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pictureBox1.Location = new System.Drawing.Point(201, 51);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(410, 253);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// button1
//
this.button1.Location = new System.Drawing.Point(338, 349);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(149, 46);
this.button1.TabIndex = 1;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button1);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
由于我在窗体上放了一个PictureBox和一个Button, InitializeComponent() 成员函数会自动初始化和记录我所创建的控件。
我们可以在Form1.Designer.cs看到我所创建的字段,如下所示。
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button button1;
执行完InitializeComponent() 后,程序会回到构造方法,然后再回到主程序Program.cs,然后窗体就会显示出来,
然后就是大家熟悉的窗体操作环节,而这写我们DIY 的代码都会在对外的Form1.cs 中。
然后,当我们关闭程序的是时候,VS 会自动清理堆中的数据,就是我们当初创建的匿名Form1 对象,此时执行:
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
这有点类似于C++中的delete 。不过我们这里是自动调用的。
然后程序最终返回主程序Program.cs,至此程序执行完毕。
至此主题讲解完毕。
如果我们要添加另一个类,就是在当前名称空间下创建一个类即可,这和控制台应用程序是一样的。
我们可以通过控制访问权限来控制访问。
而有关程序集的一般信息由以下代码控制。更改这些特性值可修改
与程序集关联的信息。即我们可以找到的AssemblyInfo.cs 中的代码。
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("WindowsFormsApp1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsFormsApp1")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("8260d835-8536-4eab-94e7-c3cf7b435afb")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
感兴趣的同学和读者,可以百度一下,这里不做过多讲解。