ZetCode

C# Windows Forms 教程

最后修改于 2025 年 5 月 13 日

我们的 C# Windows Forms 教程提供了使用 C# 和 Windows Forms 进行 GUI 编程的实践性介绍。我们不会依赖窗体设计器,而是从头开始手动构建应用程序,以加深您对框架的理解。

Windows Forms

Windows Forms,通常简称为 WinForms,是 Microsoft .NET Framework 中包含的一个图形用户界面 (GUI) 框架。它通过提供丰富的控件和功能来简化桌面应用程序开发,从而创建用户友好的界面。

借助 Windows Forms,开发人员可以设计出视觉上吸引人且易于部署和维护的应用程序。此外,与传统的基于 Windows 的应用程序相比,Windows Forms 应用程序提供了增强的安全性。

2018 年 12 月,Microsoft 宣布 Windows Forms 将成为 GitHub 上的一个开源项目,并采用 MIT 许可证。此版本使 Windows Forms 可以在 .NET Core 框架上使用,但它仍然仅限于 Windows 平台。

构建 Windows Forms 应用程序

我们将使用 .NET Core 来创建 Windows Forms 应用程序。

$ dotnet new winforms -o MyApp

使用 dotnet new winforms 命令可以创建一个新的 Windows Forms 应用程序模板。

$ dotnet run

使用 dotnet run 命令运行该应用程序。

Windows Forms 简单示例

在第一个示例中,我们在屏幕上显示一个简单的窗口。

$ dotnet new winforms -o First

我们创建了 Windows Forms 应用程序的模板。该命令还会生成 Form1.Designer.csForm1.cs 文件。我们不会使用它们,可以安全地删除它们。

Program.cs
using System.Windows.Forms;
using System.Drawing;

namespace First;

public class MyForm : Form
{
    public MyForm()
    {
        InitComponents();
    }

    private void InitComponents()
    {
        Text = "First application";
        ClientSize = new Size(800, 450);
        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

该示例在屏幕上显示一个主窗口。窗口居中显示。

using System.Windows.Forms;
using System.Drawing;

我们使用 Windows Forms 和 Drawing 命名空间。

public class MyForm : Form
{
...
}

在 Windows Forms 中,任何窗口或对话框都是一个 Form。此控件是一个基本的容器,其目的是显示其他子控件。MyForm 继承自 Form。这样,它本身就成为一个窗体。

public MyForm()
{
    InitComponents();
}

作为良好的编程实践,窗体初始化委托给 InitComponents 方法。

private void InitComponents()
{
    Text = "First application";
    ClientSize = new Size(800, 450);
    CenterToScreen();
}

TextSize 是窗体的属性。通过更改这些属性,我们可以修改我们的窗体控件。第一行在窗体控件的标题栏中显示文本“First application”。第二行设置窗体客户区的大小。CenterToScreen 方法将窗体居中显示在屏幕上。

[STAThread]
static void Main()
{
...
}

Main 方法是应用程序的入口点。Windows Forms 应用程序必须声明 [STAThread] 属性;否则,控件可能无法正常工作。这表示使用单线程单元模型而不是多线程模型。

Application.SetHighDpiMode(HighDpiMode.SystemAware);

使用 SetHighDpiMode 方法,我们确保我们的应用程序在任何显示分辨率下都能良好显示。

Application.EnableVisualStyles();

EnableVisualStyles 方法启用视觉样式。应用程序将使用内置的 Windows 主题来设置控件的样式,而不是经典的 Windows 外观。

Application.Run(new MyForm());

Run 方法启动应用程序。它开始在当前线程上运行标准的应用程序消息循环,并使指定的窗体可见。

Windows Forms 居中示例

此示例演示了如何将 Windows Forms 应用程序窗口居中显示在屏幕上。居中主窗口可提供更好的用户体验,并确保应用程序在启动时易于查看。

Program.cs
using System.Windows.Forms;
using System.Drawing;

namespace CenteredApp;

public class MyForm : Form
{
    public MyForm()
    {
        Text = "Centered App";
        ClientSize = new Size(400, 250);
        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

CenterToScreen 方法在应用程序启动时将窗口居中显示在屏幕上。这是让您的应用程序出现在用户显示器中央的一种简单方法。

Windows Forms 工具提示

工具提示是一个小矩形弹出窗口,当用户将指针悬停在控件上时,它会显示控件用途的简短描述。

Program.cs
using System.Drawing;
using System.Windows.Forms;

namespace Tooltips;

public class MyForm : Form
{
    private FlowLayoutPanel flowPanel;

    public MyForm()
    {
        InitComponents();
    }

    private void InitComponents()
    {
        Text = "Tooltips";
        ClientSize = new Size(800, 450);

        flowPanel = new FlowLayoutPanel();

        var ftip = new ToolTip();
        ftip.SetToolTip(flowPanel, "This is a FlowLayoutPanel");

        flowPanel.Dock = DockStyle.Fill;
        flowPanel.BorderStyle = BorderStyle.FixedSingle;

        var button = new Button();
        button.Text = "Button";
        button.AutoSize = true;

        var btip = new ToolTip();
        btip.SetToolTip(button, "This is a Button Control");

        var button2 = new Button();
        button2.Text = "Button 2";
        button2.AutoSize = true;

        flowPanel.Controls.Add(button);
        flowPanel.Controls.Add(button2);
        Controls.Add(flowPanel);

        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

代码示例为两个控件创建了工具提示:一个 Button 控件和一个 Form 控件。

flowPanel = new FlowLayoutPanel();

我们将两个按钮放在 FlowLayoutPanel 上。它水平或垂直地动态布局其内容。(默认尺寸为垂直。)

var ftip = new ToolTip();
ftip.SetToolTip(flowPanel, "This is a FlowLayoutPanel");

我们创建一个新的工具提示。使用 SetToolTip,我们将工具提示分配给 FlowLayoutPanel 控件。

flowPanel.Dock = DockStyle.Fill;

FlowLayoutPanel 填充了窗体控件的整个区域。

var button = new Button();
button.Text = "Button";
button.AutoSize = true;

创建一个新的 Button 控件。我们使用 Text 属性设置其文本,并自动调整其大小以适应文本大小。

var btip = new ToolTip();
btip.SetToolTip(button, "This is a Button Control");

向第一个 Button 控件添加了工具提示。

flowPanel.Controls.Add(button);
flowPanel.Controls.Add(button2);
Controls.Add(flowPanel);

将按钮添加到流面板,并将流面板添加到窗体。

Windows Forms 退出按钮

Button 控件表示一个 Windows 按钮控件。通过鼠标、Enter 键或 Spacebar(如果按钮获得焦点)可以单击它。

Program.cs
using System.Windows.Forms;
using System.Drawing;

namespace QuitButton;

class MyForm : Form
{
    private FlowLayoutPanel flowPanel = new();

    public MyForm()
    {
        InitComponents();
    }

    private void InitComponents()
    {
        Text = "Quit button";
        ClientSize = new Size(800, 450);

        flowPanel = new FlowLayoutPanel();

        flowPanel.Dock = DockStyle.Fill;
        flowPanel.BorderStyle = BorderStyle.FixedSingle;

        var button = new Button();
        button.Margin = new Padding(10, 10, 0, 0);

        button.Text = "Quit";
        button.AutoSize = true;
        button.Click += (_, _) => Close();

        flowPanel.Controls.Add(button);
        Controls.Add(flowPanel);

        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

该示例创建了一个退出按钮控件;单击按钮时,应用程序将终止。

var button = new Button();
button.Margin = new Padding(10, 10, 0, 0);

按钮的边框周围有一些边距。我们在按钮控件的左侧和上方添加了一些空间。

button.Click += (_, _) => Close();

我们将一个事件处理程序连接到 Click 事件。当我们单击按钮时,应用程序将使用 Close 方法关闭。由于我们不处理发送者对象和事件参数,我们使用丢弃(discards)。

Windows Forms 标签

Label 是一个用于显示文本或图像的简单控件。它不接收焦点。

Program.cs
using System.Drawing;
using System.Windows.Forms;

namespace LabelEx;

public class MyForm : Form
{
    public MyForm()
    {
        InitUI();
    }

    private void InitUI()
    {
        string text = @"
Spending my time
Watching the days go by
Feeling so small, I stare at the wall
Hoping that you think of me too
I'm spending my time

I try to call but I don't know what to tell you
I leave a kiss on your answering machine
Oh, help me please, is there someone who can make me
Wake up from this dream?
";

        var font = new Font("Serif", 10);

        var lyrics = new Label();
        lyrics.Parent = this;
        lyrics.Text = text;
        lyrics.Font = font;
        lyrics.Location = new Point(10, 10);
        lyrics.AutoSize = true;

        CenterToScreen();

        Text = "Label";
        AutoSize = true;
        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

该示例使用 Label 控件显示歌词。

var font = new Font("Serif", 10);

我们使用此字体显示文本。

var lyrics = new Label();
lyrics.Parent = this;
lyrics.Text = text;
lyrics.Font = font;
lyrics.Location = new Point(10, 10);
lyrics.AutoSize = true;

创建了标签控件。它位于窗体上的 x=10, y=10 坐标处。

Text = "Label";
AutoSize = true;
CenterToScreen();

主窗口自动调整大小以适应歌词。

Windows Forms 复选框

CheckBox 是一个具有两种状态的控件:开和关。它是一个带有标签或图像的框。如果 CheckBox 被选中,则用框中的勾号表示。

Program.cs
using System.Windows.Forms;
using System.Drawing;

namespace CheckBoxEx;

class MyForm : Form
{
   private FlowLayoutPanel FlowPanel = new();

    public MyForm()
    {
        InitUI();
    }

    private void InitUI()
    {
        Text = "CheckBox";
        ClientSize = new Size(450, 250);

        FlowPanel = new FlowLayoutPanel();

        var pad = new Padding(20);

        var cb = new CheckBox();
        cb.Margin = pad;
        cb.Parent = this;
        cb.Text = "Show Title";
        cb.AutoSize = true;
        cb.Checked = true;

        cb.CheckedChanged += new EventHandler(OnChanged);

        FlowPanel.Controls.Add(cb);
        Controls.Add(FlowPanel);

        CenterToScreen();
    }

    void OnChanged(object sender, EventArgs e)
    {
        if (((CheckBox )sender).Checked)
        {
            Text = "CheckBox";
        }
        else
        {
            Text = "";
        }
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

代码示例根据其状态显示或隐藏窗口的标题。

var pad = new Padding(20);

cb = new CheckBox();
cb.Margin = pad;
cb.Parent = this;
cb.Text = "Show Title";
cb.AutoSize = true;
cb.Checked = true;

应用程序启动时,我们显示标题。并将 CheckBox 控件设置为选中状态。

cb.CheckedChanged += new EventHandler(OnChanged);

当我们单击 CheckBox 控件时,会触发 CheckedChanged 事件。

void OnChanged(object sender, EventArgs e)
{
    if (((CheckBox )sender).Checked)
    {
        Text = "CheckBox";
    }
    else
    {
        Text = "";
    }
}

根据 Checked 属性的值,我们切换窗口的标题。

Windows Forms 简单菜单

菜单栏是菜单的集合。菜单对应用程序的命令进行分组。

Program.cs
using System.Drawing;
using System.Windows.Forms;

namespace MenuEx;

class MyForm : Form
{
    public MyForm()
    {
        Text = "Simple menu";

        var ms = new MenuStrip();
        ms.Parent = this;

        var fileMenuItem = new ToolStripMenuItem("&File");
        var exitMenuItem = new ToolStripMenuItem("&Exit", 
            null, (_, _) => Close());

        exitMenuItem.ShortcutKeys = Keys.Control | Keys.X;
        fileMenuItem.DropDownItems.Add(exitMenuItem);

        ms.Items.Add(fileMenuItem);
        MainMenuStrip = ms;
        ClientSize = new Size(450, 300);

        CenterToScreen();
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

在我们的示例中,我们有一个菜单栏和一个菜单。菜单中有一个菜单项。如果我们选择菜单项,应用程序将关闭。

还可以通过使用 Ctrl+X 快捷键或按 AltFE 键来关闭应用程序。

var ms = new MenuStrip();

MenuStrip 为我们的窗体创建了一个菜单系统。我们将 ToolStripMenuItem 对象添加到 MenuStrip 中,这些对象代表菜单结构中的各个菜单命令。每个 ToolStripMenuItem 都可以是应用程序的命令,也可以是其他子菜单项的父菜单。

var fileMenuItem = new ToolStripMenuItem("&File");

在这里,我们使用 ToolStripMenuItem 创建一个菜单。

var exitMenuItem = new ToolStripMenuItem("&Exit", 
    null, (_, _) => Close());

此行创建退出菜单项。

exitMenuItem.ShortcutKeys = Keys.Control | Keys.X;

我们为退出菜单项提供了一个快捷方式。

fileMenuItem.DropDownItems.Add(exitMenuItem);

退出菜单项已添加到菜单对象的下拉项中。

ms.Items.Add(fileMenuItem);

在这里,我们将菜单对象添加到菜单栏中。

MainMenuStrip = ms;

MenuStrip 被连接到窗体。换句话说,菜单栏被添加到应用程序的主窗口。

Windows Forms 绘制矩形

绘制使用 Windows Forms 提供的绘图 API 完成。绘制在一个方法内完成,我们将其连接到 Paint 事件。

Program.cs
using System.Drawing;

using System.Windows.Forms;

namespace RectanglesEx;

class Program : Form
{
    public Program()
    {
        InitUI();
    }

    private void InitUI()
    {
        Text = "Rectangles";
        Paint += new PaintEventHandler(OnPaint);

        ClientSize = new Size(550, 450);
        CenterToScreen();
    }

    void OnPaint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;

        g.FillRectangle(Brushes.Sienna, 10, 15, 90, 60);
        g.FillRectangle(Brushes.Green, 130, 15, 90, 60);
        g.FillRectangle(Brushes.Maroon, 250, 15, 90, 60);
        g.FillRectangle(Brushes.Chocolate, 10, 105, 90, 60);
        g.FillRectangle(Brushes.Gray, 130, 105, 90, 60);
        g.FillRectangle(Brushes.Coral, 250, 105, 90, 60);
        g.FillRectangle(Brushes.Brown, 10, 195, 90, 60);
        g.FillRectangle(Brushes.Teal, 130, 195, 90, 60);
        g.FillRectangle(Brushes.Goldenrod, 250, 195, 90, 60);
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new Program());
    }
}

我们绘制了九个具有九种不同颜色的矩形。

Paint += new PaintEventHandler(OnPaint);

Paint 事件被传递到 OnPaint 方法。

void OnPaint(object sender, PaintEventArgs e)
{
    ...
}

这是 OnPaint 方法的签名。

Graphics g = e.Graphics;

为了在窗体上绘图,我们必须获取 Graphics 对象。在窗体上绘图实际上是调用 Graphics 对象的各种方法。

g.FillRectangle(Brushes.Sienna, 10, 15, 90, 60);

FillRectagle 方法用画笔填充指定的矩形。画笔可以是颜色或图案。有一些预定义的颜色可用。我们可以从 Brushes 枚举中获取它们。最后四个值是矩形左上角的 x、y 坐标以及矩形的宽度和高度。

Windows Forms 消息框

消息框通常在 Windows Forms 应用程序中使用,用于显示信息、警告、错误或提示用户进行确认。MessageBox 类提供了静态方法来显示具有各种按钮和图标的不同类型消息对话框。

Program.cs
using System.Windows.Forms;
using System.Drawing;

namespace MessageBoxEx;

class MyForm : Form
{
    public MyForm()
    {
        Text = "MessageBox demo";
        ClientSize = new Size(400, 200);
        CenterToScreen();

        var btn = new Button();
        btn.Text = "Show Message Boxes";
        btn.AutoSize = true;
        btn.Click += (s, e) => ShowMessages();
        Controls.Add(btn);
    }

    private void ShowMessages()
    {
        MessageBox.Show("This is an information message.", "Info");
        MessageBox.Show("This is a warning message.", "Warning", 
            MessageBoxButtons.OK, MessageBoxIcon.Warning);
        MessageBox.Show("This is an error message.", "Error", 
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        var result = MessageBox.Show("Do you want to continue?", 
            "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

        if (result == DialogResult.Yes)
        {
            MessageBox.Show("You chose Yes.");
        }
        else
        {
            MessageBox.Show("You chose No.");
        }
    }

    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.Run(new MyForm());
    }
}

此示例演示了如何显示不同类型的消息框:信息消息、警告、错误以及带有是/否选项的问题对话框。MessageBox 类允许您自定义对话框的标题、按钮和图标,使其成为应用程序中用户交互和反馈的多功能工具。

来源

Windows Forms 文档

在本文中,我们使用 C# 和 Windows Forms 创建了简单的 GUI 应用程序。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出所有 C# 教程