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

C# WinForm 控制項隨表單縮放自動調整大小與位置 (Anchor/Dock 替代方案)

     編輯:關於C#

WinForm 內建 Anchor、Dock、TableLayoutPanel、FlowLayoutPanel 等佈局機制,大多數情況已足夠。但若需「所有控制項依比例縮放(含字體大小)」或「巢狀容器遞迴調整」,可參考本文實作:在 Form.Load 記錄初始狀態,SizeChanged 依比例重新計算位置與尺寸。

核心邏輯

  1. Form.Load:遞迴遍歷所有控制項,記錄 Location、Size、表單初始 ClientSize。
  2. Form.SizeChanged:計算寬高縮放比 scaleX = CurrentWidth / InitialWidth、scaleY = CurrentHeight / InitialHeight。
  3. 遞迴套用:control.Location = new Point((int)(origX * scaleX), (int)(origY * scaleY));control.Size = new Size((int)(origW * scaleX), (int)(origH * scaleY))。
  4. 縮小時啟用 AutoScroll,避免控制項疊加。

完整程式碼 (簡化版)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

public class AutoScaleForm : Form
{
    private readonly Dictionary _initialStates = new();
    private Size _initialFormSize;
    private bool _initialized;

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        _initialFormSize = ClientSize;
        RecordInitialStates(this);
        _initialized = true;
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        if (!_initialized) return;

        if (ClientSize.Width < _initialFormSize.Width || ClientSize.Height < _initialFormSize.Height)
        {
            AutoScroll = true;
            RestoreInitialStates(this);
        }
        else
        {
            AutoScroll = false;
            ApplyScaling(this);
        }
    }

    private void RecordInitialStates(Control container)
    {
        foreach (Control c in container.Controls)
        {
            if (!_initialStates.ContainsKey(c))
                _initialStates[c] = c.Bounds; // 記錄 Location + Size
            if (c.HasChildren) RecordInitialStates(c);
        }
    }

    private void RestoreInitialStates(Control container)
    {
        foreach (Control c in container.Controls)
        {
            if (_initialStates.TryGetValue(c, out var bounds))
                c.Bounds = bounds;
            if (c.HasChildren) RestoreInitialStates(c);
        }
    }

    private void ApplyScaling(Control container)
    {
        float scaleX = (float)ClientSize.Width / _initialFormSize.Width;
        float scaleY = (float)ClientSize.Height / _initialFormSize.Height;

        foreach (Control c in container.Controls)
        {
            if (_initialStates.TryGetValue(c, out var orig))
            {
                c.Bounds = new Rectangle(
                    (int)(orig.X * scaleX), (int)(orig.Y * scaleY),
                    (int)(orig.Width * scaleX), (int)(orig.Height * scaleY));
            }
            if (c.HasChildren) ApplyScaling(c);
        }
    }
}

關鍵細節與改進建議

問題改進方向
字體不縮放同步縮放 Font = new Font(origFont.FontFamily, origFont.Size * Math.Min(scaleX, scaleY), origFont.Style)
最小尺寸限制設定 MinimumSize 或在縮放前檢查 scale < 0.5f 停止縮放
特定控制項不想縮放加入 Tag = "NoScale" 判斷跳過
效能:頻繁 SizeChanged 觸發使用 ResizeBegin/ResizeEnd 或 `Timer` 去抖動
高 DPI 模糊專案啟用 Per-Monitor DPI Aware (app.manifest + `SetProcessDpiAwarenessContext`)

何時使用此方案 vs 內建佈局

結語

比例縮放屬於「像素級佈局」,適合特定領域(圖形、報表、嵌入式螢幕)。現代商務表單開發,優先使用流式佈局(Anchor/Dock/TableLayoutPanel)配合高 DPI 感知,維護性與使用者體驗更佳。本文代碼可作為舊專案遷移或特殊需求的參考實作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景建議
固定比例縮放、字體同步放大、報表預覽、圖形編輯器本文比例縮放方案
一般資料輸入表單、工具列、狀態列Anchor/Dock + TableLayoutPanel
響應式佈局 (斷點切換)WPF/UWP/Blazor/WinUI 3