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

WinForms中ContextMenuStrip的DPI感知异常问题求助

WinForms PerMonitorV2下ContextMenuStrip DPI适配问题解决方案

1. 确认项目DPI感知配置完全生效

首先确保项目的DPI配置正确且生效:

  • 检查csproj文件中的配置:
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
  • 在Program.cs中手动设置进程DPI感知(避免SDK自动处理的遗漏):
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDpiAwarenessContext(int dpiFlag);

static void Main()
{
    // 启用PerMonitorV2模式
    SetProcessDpiAwarenessContext(-4);
    ApplicationConfiguration.Initialize();
    Application.Run(new MainForm());
}

2. 监听窗口DPI变更,强制更新ContextMenuStrip

ContextMenuStrip不会自动跟随窗口DPI变更,需要在窗口的DpiChanged事件中手动更新:
在窗体代码中添加以下逻辑:

protected override void OnDpiChanged(DpiChangedEventArgs e)
{
    base.OnDpiChanged(e);
    UpdateContextMenuStripDpi(yourContextMenuStrip, e.DeviceDpiNew);
}

private void UpdateContextMenuStripDpi(ContextMenuStrip cms, int newDpi)
{
    float scaleFactor = newDpi / 96f;
    // 更新菜单字体
    cms.Font = new Font(cms.Font.FontFamily, cms.Font.Size * scaleFactor, cms.Font.Style);
    
    // 递归更新所有子项及子菜单
    cms.SuspendLayout();
    foreach (ToolStripItem item in cms.Items)
    {
        if (item is ToolStripMenuItem menuItem && menuItem.DropDown is ContextMenuStrip subCms)
        {
            UpdateContextMenuStripDpi(subCms, newDpi);
        }
        item.Invalidate();
    }
    cms.ResumeLayout(true);
    cms.PerformLayout();
}

3. 修复勾选标记的缩放问题

ToolStripMenuItem的勾选标记默认不会随DPI缩放,需要手动生成适配尺寸的标记图像:
添加以下方法,并在UpdateContextMenuStripDpi中调用:

private void UpdateMenuItemCheckMark(ToolStripMenuItem item, int dpi)
{
    float scale = dpi / 96f;
    int newSize = (int)(16 * scale); // 默认勾选标记尺寸为16x16,按DPI缩放
    
    using (Bitmap bmp = new Bitmap(newSize, newSize))
    using (Graphics g = Graphics.FromImage(bmp))
    {
        g.ScaleTransform(scale, scale);
        // 绘制系统默认勾选标记
        ToolStripRenderer.Default.DrawItemCheck(g, new ToolStripItemImageRenderEventArgs(g, item, SystemIcons.Check.ToBitmap(), new Point(0, 0)));
        item.Image = new Bitmap(bmp);
    }
}

修改UpdateContextMenuStripDpi中的循环逻辑:

if (item is ToolStripMenuItem menuItem)
{
    UpdateMenuItemCheckMark(menuItem, newDpi);
    if (menuItem.DropDown is ContextMenuStrip subCms)
    {
        UpdateContextMenuStripDpi(subCms, newDpi);
    }
    item.Invalidate();
}

4. 处理跨显示器移动后的尺寸还原

监听窗体的LocationChanged事件,确保窗口移动时实时检查当前显示器DPI并更新:

public MainForm()
{
    InitializeComponent();
    LocationChanged += MainForm_LocationChanged;
}

private void MainForm_LocationChanged(object sender, EventArgs e)
{
    var currentScreen = Screen.FromControl(this);
    UpdateContextMenuStripDpi(yourContextMenuStrip, currentScreen.DeviceDpi);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:45:35