VS/C# 可视化编程:WinForms窗体基础操作

参考文献
[1] Microsoft. 适用于 Windows 窗体的 .NET 桌面指南[EB/OL]. [2022-9-17]. https://docs.microsoft.com/zh-cn/dotnet/desktop/winforms/getting-started-with-windows-forms?view=netframeworkdesktop-4.8.
[2] 明日科技. C#从入门到精通[M]. 第5版. 北京:清华大学出版社, 2019.

0 WinForms简述

Windows 窗体(WinForms)应用程序是基于 .NET Framework 的智能客户端组件,可通过 Visual Studio 创建。windows窗体应用程序可显示信息、请求用户输入以及通过网络与远程计算机通信,构建丰富的交互式用户界面。

1窗体

窗体(Form)是一种可视图面,可在其上对用户显示信息。通常通过将控件放置在窗体上并开发对用户操作(如鼠标单击或按键)的响应(即事件)来生成 Windows 窗体应用程序。窗体是对象,基于 System.Windows.Forms 命名空间中的类生成,窗体类定义了生成窗体的模板,每实例化一个窗体类,就产生一个窗体。
MDI窗体:MDI(Multiple Document Interface,多文档窗体)和单文档SDI相对,二者区别在于MDI通常是一个带有菜单的主界面,允许用户同时打开多个窗体;而SDI只能打开一个窗体。MDI窗体示例见下图。

MDIparent:父窗体 MDIchild:子窗体

在这里插入图片描述
多窗体项目必须要设置先运行的窗体,即启动窗体。项目的启动窗体是在Program.cs文件的Run()方法中设置的。Run()方法用于在当前线程上开始运行标准应用程序,并使指定窗体可见。

public static void Run(Form mainForm)	//mainForm为要设为启动窗体的窗体。

窗体的组成要素可通过窗体的“属性”面板(或代码)进行设置。常见属性设置见下表。

属性功能
Icon窗体图标更换
FormBorderStyle标题栏隐藏
StartPositon窗体显示位置
Size窗体大小
BackgroundImage设置图像背景

在【属性】中找到这几个值比较麻烦,因为属性栏并没有提供搜索选项。不过可以将属性【按分类顺序】改为【按字母顺序】,然后按照首字母查找。
在这里插入图片描述

通过new创建了一个新窗体后,该窗体的Visible属性默认是false,顾不进行显示。有多种方法可以实现子窗体的打开与隐藏。

Form form = new Form();	
form.Show();	//显示窗体,这种方法显示的子窗体与主窗体互不影响
form.Showdialog();	//显示窗体,只能在关闭子窗体后才能操作主窗体
form.Activate(); //在最前面显示窗体
form.Hide();	//隐藏窗体

Windows是事件驱动的操作系统,对Form类的任何交互都是基于事件来实现的。Form类提供了大量的事件用于响应对窗体执行的各种操作。几种窗体常用事件。

事件触发方式
click(单击)单击窗口时触发
load(加载)窗体加载时触发
FormClosing(关闭)窗体关闭时触发

2组件

组件(component)在某些方面与控件相似, 与控件不同的地方在于,组件并非用户可在窗体中查看的项目,相反,这将提供可使用代码触发的某些行为。控件是带有可视化表示形式的组件。

3控件

控件(Control)是离散的用户界面元素,用于显示数据或接受数据输入。控件是带有可视化表示形式的组件。
Windows应用程序控件的基类是位于System.Windows.Forms命名空间的Control类。Control类定义了控件类的共同属性、方法和事件,其他的控件类都直接或间接地派生自这个基类。
常用控件可以分为文本类控件、选择类控件、分组控件、菜单控件、工具栏控件以及状态栏控件。
在这里插入图片描述
自定义控件名称需要遵循控件的命名规范。
在这里插入图片描述

方法在引用时需在【事件】中进行配置(在控件中添加事件):
在这里插入图片描述

此时会在Form.cs中被引用的方法左上角会自动显示:
在这里插入图片描述

4事件

事件(Event)是可以通过代码响应或“处理”的操作。 事件可由用户操作(例如单击鼠标或按某个键)、程序代码或系统生成。
事件驱动的应用程序执行代码以响应事件。 每个窗体和控件都公开一组预定义事件,你可根据这些事件进行编程。 如果发生其中一个事件并且在相关联的事件处理程序中有代码,则调用该代码。
对象引发的事件类型会发生变化,但对于大多数控件,很多类型都是通用的。 例如,大多数对象都会处理 Click 事件。 此外,许多事件会与其他事件同时发生。

事件处理程序是绑定到事件的方法, 引发事件时,事件处理程序内的代码将会执行。

 private void inputTextBox1_KeyPress(object sender, EventArgs e)
 {
 	//主体
 }

事件处理程序提供下述两类参数。

  • object sender:sender提供对引发事件的对象的引用,上例中控件对象为inputTextBox1;
  • EventArgs e:e传递特定于要处理的事件的对象,上例中为获取当前按下来的键值。
    当第二个参数具有相同的对象类型时,可使用同一事件处理程序来处理这两个事件。

5线程

5.1概述

默认情况下,系统为应用程序分配一个线程(thread),即主线程。主线程就是Main()方法所在的线程,主线程即消息循环。构造函数中的Run()方法的功能为在当前线程上启动应用程序消息循环。

 static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

一般情况下,所谓UI线程就是主线程(除非用户进行了修改),即使启动多个窗口也是都在主线程上,并非一个窗口对应一个线程。
单线程环境下,如果做复杂处理,则会出现假死状态(即堵塞),因为一条线程同时只能做一件事。可以通过设计多线程来处理耗时的任务,这样就不会使主界面出现无响应的情况,新创建的线程被称为子线程工作线程

5.2跨线程访问

控件由主线程创建,由于程序默认是不允许跨线程访问的,新线程想要访问主线程资源,最简单的方式是在要访问的窗口的构造函数中关闭跨线程访问检查,见下。

public Form1()
{
    InitializeComponent();
    CheckForIllegalCrossThreadCalls = false;	//关闭跨线程访问检查。
}

6计时器

计时器(Timer)按用户定义的时间间隔引发事件。.NET支持多个计时器类。

  • System.Windows.Forms.Timer
    简述:该计时器是一个Windows 窗体组件,被设计为单线程环境,基于UI线程运行,在Tick事件中执行相关操作。若Tick事件中执行任务量过多会导致堵塞,现象为UI无响应。如果单次执行时间超过设置的间隔时间,则下次执行会延后直至本次执行完成,因而精度较差。
    精度:55ms

  • System.Threading.Timer
    简述:该计时器提供以指定的时间间隔对线程池线程执行方法的机制。

  • System.Timers.Timer
    简述:该计时器基于服务器,用于多线程环境中的工作线程,可以在线程之间移动以处理引发的Elapsed事件。
    精度:1ms

7基础操作

7.1新建项目

在这里插入图片描述

有C#和VB(.NET Framework),注意区别。

新建项目并添加窗体后,在解决方案资源管理器中生成了Form.Designer.cs、 Form.cs 、Form1.resx和Program.cs四个文件。

  1. Form.cs中存放用户编写的窗体操作代码;
  2. Form.Designer.cs 是对窗体画面布局的设计代码,由Visual Studio自动生成;
  3. Form1.resx包含表单所保存的图像等资源;
  4. Program.cs中存放main方法,是程序的入口点;

要注意的是在解决方案资源管理器中双击Form.cs只会弹出设计器而非代码页面,需右击Form.cs,在弹出的菜单中点击【查看代码】:
在这里插入图片描述
新建一个winform应用程序,默认会带入以下空间的引用:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

将自动生成**分布类(partial class)**及其构造函数:

namespace test
{
    public partial class Form1 : Form	//分布类
    {
        public Form1()	//构造函数
        {
            InitializeComponent();
        }

    }
}

可以拆分一个类,使其分布于多个独立文件中,该类即称作分布类,使用 partial 关键字修饰符。VS在创建windows窗体时会拆分类定义,这样当使用自动生成的源文件时,可以添加代码而不需要重新创建源文件。

构造函数中的InitializeComponent()方法反映了窗体设计器中窗体和控件的属性。

7.2窗体另存为

窗体另存为并不是以项目为单位进行储存,而是分为3个文件:
在这里插入图片描述
因此必须创建新项目并放入这三个文件。

一种可以达成此目的的方法:

  1. 新建项目,然后退出,打开保存项目的文件夹;
  2. 将另存为的三个文件名修改为默认名称(Form1),然后替换文件夹中的同名文件,注意新建项目中,在未操作的情况下,文件夹中没有Form1.resx

下图为新建项目目录。
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值