欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

详细讲解基于.NET的WinForm桌面应用程序的运行过程和代码原理-C# 7

程序员文章站 2022-05-28 09:02:02
...

本博客详细讲解基于.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");
        }
    }
}


详细讲解基于.NET的WinForm桌面应用程序的运行过程和代码原理-C# 7
桌面程序和控制台程序相同有一个入口程序,及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 中。
详细讲解基于.NET的WinForm桌面应用程序的运行过程和代码原理-C# 7

然后,当我们关闭程序的是时候,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")]

感兴趣的同学和读者,可以百度一下,这里不做过多讲解。