首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 深度入門(四):Windows Forms 桌面應用程式開發實戰

     編輯:關於C語言

前言:WinForms 快速開發桌面應用的經典選擇

Windows Forms (WinForms) 是 .NET Framework 早期提供的事件驅動桌面 UI 框架,雖然不如 WPF/MAUI 現代,但以「所見即所得」設計師、豐富控制項、成熟生態、低學習曲線,仍是企業內部工具、維護專案、快速原型的主流選擇。本章完整演示從專案建立、介面設計、事件處理到部署的標準流程。

一、建立 WinForms 專案

  1. VS 選單:檔案 → 新增 → 專案
  2. 搜尋「Windows Forms」→ 選擇 Windows Forms 應用程式(標籤:.NET 8.0 / .NET Framework)
  3. 專案名稱:FileBrowserDemo
  4. 目標框架:.NET 8.0 (Windows) 或 .NET Framework 4.8.1

專案檔差異

<!-- .NET 8.0 (SDK 風格) -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>

<!-- .NET Framework (舊格式) -->
<Project>
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>
</Project>

二、表單設計師與介面佈局

設計師介面

  • Form1.cs [設計]:拖放控制項、調整屬性、事件綁定
  • 工具箱 (Ctrl+Alt+X):所有 Windows Forms 控制項分類
  • 屬性視窗 (F4):選中控制項後設定屬性、事件(閃電圖示)
  • 文件大綱 (Ctrl+Alt+T):控制項階層結構、Z-order 調整

實作:檔案瀏覽器介面

控制項名稱關鍵屬性用途
ButtonbtnBrowseText="瀏覽..."觸發開啟檔案對話方塊
TextBoxtxtFilePathReadOnly=True, Anchor=Top,Left,Right顯示選取檔案完整路徑
OpenFileDialogofdFileFilter="文字檔|*.txt|所有檔案|*.*", Title="選擇檔案"檔案選取對話方塊(非視覺元件)

佈局技巧

  • Anchor:固定控制項相對表單邊緣位置(預設 Top,Left)
  • Dock:填滿容器區域(Fill, Top, Bottom, Left, Right)
  • TableLayoutPanel / FlowLayoutPanel:響應式網格/流式佈局
  • AutoSize / AutoSizeMode:依內容自動調整尺寸

三、事件驅動程式設計

雙擊產生事件處理器

在設計師雙擊 Button → 自動產生 btnBrowse_Click 並切換至程式碼視圖:

private void btnBrowse_Click(object sender, EventArgs e)
{
    if (ofdFile.ShowDialog() == DialogResult.OK)
    {
        txtFilePath.Text = ofdFile.FileName;
    }
}

事件模式深度解析

// 標準事件簽章
public delegate void EventHandler(object sender, EventArgs e);

// 產生器語法 (C# 2.0+)
btnBrowse.Click += new EventHandler(btnBrowse_Click);
// Lambda 簡寫 (C# 3.0+)
btnBrowse.Click += (s, e) => { /* ... */ };
// 方法群組轉換
btnBrowse.Click += btnBrowse_Click;

常用事件分類

類別事件觸發時機
滑鼠Click, DoubleClick, MouseDown/Up/Move/Enter/Leave滑鼠互動
鍵盤KeyDown/Up/Press, PreviewKeyDown鍵盤輸入
焦點Enter, Leave, GotFocus, LostFocus焦點移動
生命週期Load, Shown, FormClosing, FormClosed表單狀態變化
資料TextChanged, Validating, Validated內容變更/驗證
繪圖Paint需重繪時

四、程式碼架構:分離關注點

Form1.cs 結構

namespace FileBrowserDemo
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent(); // 設計師產生,勿手動修改
        }

        // 事件處理器 - 只負責 UI 互動
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (ofdFile.ShowDialog() == DialogResult.OK)
            {
                txtFilePath.Text = ofdFile.FileName;
                // 業務邏輯委派給服務類別
                FileService.ProcessFile(ofdFile.FileName);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            // 初始化邏輯
        }
    }
}

服務類別分離

public static class FileService
{
    public static void ProcessFile(string path)
    {
        // 實際業務邏輯:讀取、解析、驗證...
        // 易於單元測試、復用、維護
    }
}

五、資料繫結:減少樣板程式碼

// 簡單繫結
txtName.DataBindings.Add("Text", customer, "Name", true, DataSourceUpdateMode.OnPropertyChanged);

// 複雜繫結 (DataGridView)
var bindingSource = new BindingSource();
bindingSource.DataSource = typeof(Customer);
dgvCustomers.DataSource = bindingSource;

// 物件清單繫結
bindingSource.DataSource = customerList; // List

INotifyPropertyChanged 實作

public class Customer : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string prop = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}

六、多執行緒與 UI 回應性

錯誤示範:阻塞 UI 執行緒

private void btnBad_Click(object sender, EventArgs e)
{
    // UI 凍結 5 秒,使用者以為當機
    Thread.Sleep(5000); 
    MessageBox.Show("完成");
}

正確模式:Task + async/await

private async void btnGood_Click(object sender, EventArgs e)
{
    btnGood.Enabled = false;
    try
    {
        await Task.Run(() => HeavyWork());
        MessageBox.Show("完成");
    }
    finally
    {
        btnGood.Enabled = true;
    }
}

private void HeavyWork()
{
    Thread.Sleep(5000); // 背景執行緒睡眠不影響 UI
    // 跨執行緒存取 UI 需 Invoke
    // this.Invoke(() => lblStatus.Text = "處理中...");
}

Progress<T> 回報進度

private async void btnProgress_Click(object sender, EventArgs e)
{
    var progress = new Progress(p => progressBar.Value = p);
    await Task.Run(() => 
    {
        for (int i = 0; i <= 100; i += 10)
        {
            Thread.Sleep(200);
            progress.Report(i); // 自動切回 UI 執行緒
        }
    });
}

七、部署與發行

發行模式比較

模式特點適用場景
Framework-dependent需目標機安裝 .NET Runtime,檔案小企業環境、統一管理 Runtime
Self-contained包含 Runtime,無需安裝,檔案大 (≈60MB+)無法安裝 Runtime 的環境
Single-file單一 .exe,解壓至暫存目錄執行簡單分發、工具類程式
Trimmed / AOT移除未使用組件 / 提前編譯原生碼極致啟動速度、體積優化

發行命令

# Framework-dependent
dotnet publish -c Release -r win-x64 --self-contained false

# Self-contained single-file
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true

# 安裝程式建立 (第三方工具)
# WiX Toolset, Inno Setup, Advanced Installer, InstallShield

八、常見問題與最佳實踐

  1. 跨執行緒 UI 存取:必須用 Control.Invoke/BeginInvoke 或 Progress<T>、SynchronizationContext
  2. 資源洩漏:IDisposable 物件 (Graphics, Pen, Brush, FileStream) 必須 using 或 Dispose()
  3. 事件記憶體洩漏:表單關閉時取消訂閱長壽命物件事件,或用 WeakEventPattern
  4. DPI 感知:專案屬性 → 應用程式 → 高 DPI 設定 → 勾選「每顯示器 DPI 感知」
  5. 全域例外處理:Application.ThreadException + AppDomain.CurrentDomain.UnhandledException
  6. 設計師程式碼:InitializeComponent 區域勿手動修改,複雜邏輯移至 OnLoad、建構函式或獨立方法

總結

WinForms 以直觀的設計師、豐富的控制項、成熟的事件模型,支撐了無數企業桌面應用。掌握「介面設計 → 事件處理 → 業務分離 → 非同步 UI → 正確部署」完整流程,配合現代 C# 語法 (async/await, Pattern Matching, Record) 與 .NET 8+ 執行階段優化,能開發出高品質、易維護的桌面應用。下一章將探討類別庫開發與 NuGet 套件發佈,實現程式碼跨專案復用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved