You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:C# WinForms动态按钮网格在125% DPI缩放时布局异常

解决方案

完全可以实现仅缩放按钮字体、保持按钮尺寸不变的需求,以下是针对.NET 4.8 WinForms的具体实现步骤:

1. 确认DPI感知配置正确

确保app.manifest中已正确启用PerMonitorV2 DPI感知,避免系统强制缩放导致布局混乱:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
    <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
  </windowsSettings>
</application>

注意:如果manifest中原有其他dpiAware配置,需删除或替换为上述内容,避免冲突。

2. 禁用自动控件缩放

将主窗体及所有容器控件(如Panel、TableLayoutPanel)的AutoScaleMode设为None,防止框架自动缩放控件尺寸:

public MainForm()
{
    InitializeComponent();
    this.AutoScaleMode = AutoScaleMode.None;
    // 若使用容器控件,同步设置其AutoScaleMode
    panelContainer.AutoScaleMode = AutoScaleMode.None;
    
    // 注册DPI变化事件,应对跨显示器移动场景
    this.DpiChanged += MainForm_DpiChanged;
    // 初始化按钮网格
    CreateButtonGrid();
}

3. 动态生成按钮时手动控制字体缩放

基于当前显示器的DPI缩放系数,计算按钮字体的缩放大小,同时固定按钮的尺寸:

private void CreateButtonGrid()
{
    // 获取当前DPI缩放比例(标准DPI为96)
    float dpiScale = this.DeviceDpi / 96f;
    // 100%缩放时的基础字体大小
    float baseFontSize = 12f;
    // 计算缩放后的字体大小
    float scaledFontSize = baseFontSize * dpiScale;

    // 固定按钮尺寸(100%缩放时的大小)
    Size fixedButtonSize = new Size(80, 30);
    // 按钮间间距
    int buttonSpacing = 5;
    // 网格行列数
    int gridCols = 5;
    int gridRows = 4;

    for (int row = 0; row < gridRows; row++)
    {
        for (int col = 0; col < gridCols; col++)
        {
            Button btn = new Button();
            btn.Text = $"Btn {row+1}-{col+1}";
            // 设置缩放后的字体
            btn.Font = new Font(btn.Font.FontFamily, scaledFontSize, btn.Font.Style);
            // 固定按钮尺寸
            btn.Size = fixedButtonSize;
            // 计算按钮位置
            btn.Location = new Point(
                col * (fixedButtonSize.Width + buttonSpacing),
                row * (fixedButtonSize.Height + buttonSpacing)
            );
            panelContainer.Controls.Add(btn);
        }
    }
}

4. 响应DPI变化事件更新字体

当窗体在不同DPI的显示器间移动时,实时更新按钮字体,确保布局一致性:

private void MainForm_DpiChanged(object sender, DpiChangedEventArgs e)
{
    float newDpiScale = e.DeviceDpiNew / 96f;
    float baseFontSize = 12f;
    float scaledFontSize = baseFontSize * newDpiScale;

    // 遍历所有按钮更新字体
    foreach (Control ctrl in panelContainer.Controls)
    {
        if (ctrl is Button btn)
        {
            btn.Font = new Font(btn.Font.FontFamily, scaledFontSize, btn.Font.Style);
            // 强制保持按钮尺寸不变
            btn.Size = new Size(80, 30);
        }
    }
    // 重新定位按钮,避免间距错位
    RepositionButtons();
}

private void RepositionButtons()
{
    Size fixedButtonSize = new Size(80, 30);
    int buttonSpacing = 5;
    int gridCols = 5;
    int currentCol = 0;
    int currentRow = 0;

    // 按原有顺序重新排列按钮
    foreach (Button btn in panelContainer.Controls.OfType<Button>().OrderBy(b => b.Location.Y).ThenBy(b => b.Location.X))
    {
        btn.Location = new Point(
            currentCol * (fixedButtonSize.Width + buttonSpacing),
            currentRow * (fixedButtonSize.Height + buttonSpacing)
        );
        currentCol++;
        if (currentCol >= gridCols)
        {
            currentCol = 0;
            currentRow++;
        }
    }
}

关键说明

  • 该方案通过手动计算DPI缩放系数控制字体大小,完全避免了按钮尺寸被自动缩放,确保在100%/125%等不同缩放级别下按钮外观一致。
  • 若使用TableLayoutPanel托管按钮,需将其列宽、行高设为固定值(对应100%缩放时的按钮尺寸),并禁用其自动缩放,布局逻辑会更简洁。

内容的提问来源于stack exchange,提问作者Nir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 09:25:20