Debugger Visualizer Winform ToolStripDropDownMenu ComboBox 仅在首次显示时显示项目

Debugger Visualizer Winform ToolStripDropDownMenu ComboBox only shows items when first shown

我有一个 Visual Studio 调试器可视化程序项目,当我将 ToolStripComboBox 添加到 ToolStripDropDownMenu 时,组合框的项目仅在第一次显示表单时出现。

像这样:

显示问题的最基本版本的 winform 代码是这样的:

public class MyVisualizerDialog : Form
{
    public MyVisualizerDialog()
    {
        var toolStripComboBox = new ToolStripComboBox
        {
            Items = { "One", "Two", "Three" }
        };

        var toolStripDownDown = new ToolStripDropDownMenu
        {
            Items = { toolStripComboBox }
        };

        var toolStrip = new ToolStrip
        {
            Items =
            {
                new ToolStripMenuItem("Options")
                {
                    DropDown = toolStripDownDown
                }
            }
        };

        Controls.Add(toolStrip);
    }
}

那么可视化代码就是:

public class MyVisualizer : DialogDebuggerVisualizer
{
    protected override void Show(
        IDialogVisualizerService windowService,
        IVisualizerObjectProvider objectProvider)
    {
        windowService.ShowDialog(
            new MyVisualizerDialog());
    }
}

一些额外的细节:

有什么想法吗?!任何人都知道 IDialogVisualizerService 处理控件或其他方式的一些问题?!

感谢阅读:)

看起来,当调试器可视化器关闭时 - 这是在调试器端处理的,而不是在调试器端处理的 - DropDown 被破坏但 ToolStripManager 不知道它并且它发现本身带有一个它不知道如何管理的无效句柄。

由于 ToolStripManager 在设计模式下也处于活动状态,这会在整个设计器界面传播问题:您可能会发现某些 DropDown 项目在调试器可视化工具关闭后仍然有效,但您可能无法添加其他项目ToolStripComboBox 项在任何地方。
如果你坚持,那么那些看起来有效的可能不再有效。

请注意,此错误行为可能会转化为 ComboBox 对象;不是直接,而是当您尝试通过界面访问他们的 Items 集合时。
它还可能会阻止项目编译。

显式处理在调试器可视化器端创建的 Form 对象,可以部分解决调试器端的问题,但事实证明,在调试器可视化器端并不能解决问题。

一个简单的解决方案是避免设置 ToolStripMenuItem 的 DropDown 对象,而是使用 MenuStrip,将 Items 添加到 ToolStripDownDown。


Create custom data visualizers
Visualizer Security Considerations


示例调试器可视化工具(简单图像可视化工具),用于测试行为。

▶ 创建一个 Class 图书馆项目,Target Framework 设置为 .Net FrameworkAnyCPU 配置文件。

▶ 添加对 [Visual Studio install Path]\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.DebuggerVisualizers.dllSystem.Windows.Forms 的引用。

▶ 将 .dll 编译为 Release

▶ 将 .dll 复制到当前 Visual Studio 安装路径的 \Common7\Packages\Debugger\Visualizers 目录。

▶ 启动调试会话,在 Image/Bitmap 属性 为 set/loaded 的位置添加断点,然后使用放大镜工具打开预览。

using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualStudio.DebuggerVisualizers;

[assembly: DebuggerVisualizer(
    typeof(ImageVisualizer.DebuggerSide), 
    typeof(VisualizerObjectSource), Target = typeof(Image), Description = "Test Visualizer")]
namespace TestVisualizer
{
    public class DebuggerSide : DialogDebuggerVisualizer
    {
        override protected void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            var image = (Image)objectProvider.GetObject();
            var form = new Form();
            form.ClientSize = new Size(image.Width, image.Height);
            form.FormBorderStyle = FormBorderStyle.FixedSingle;
            form.SuspendLayout();

            // -------   WORKING CODE   ---------------
            var menuStrip = new MenuStrip() { };
            var tsComboBox = new ToolStripComboBox { Items = { "One", "Two", "Three" } };
            var toolStripDownDown = new ToolStripMenuItem() { Text = "Options" };
            toolStripDownDown.DropDownItems.AddRange(new ToolStripItem[] { tsComboBox });
            menuStrip.Items.AddRange(new ToolStripItem[] { toolStripDownDown });
            // -------   WORKING CODE   ---------------

            // -------   BAD CODE   ---------------
            //var toolStripComboBox = new ToolStripComboBox { Items = { "One", "Two", "Three" } };
            //var toolStripDownDown = new ToolStripDropDownMenu { Items = { toolStripComboBox } };
            //var toolStrip = new ToolStrip {
            //    Items = { new ToolStripMenuItem("Options") { DropDown = toolStripDownDown } }
            //};

            // -------   BAD CODE   ---------------

            var pBox = new PictureBox() { Image = image, Dock = DockStyle.Fill };

            //form.Controls.Add(toolStrip);
            form.Controls.Add(menuStrip);
            form.Controls.Add(pBox);
            form.MainMenuStrip = menuStrip;
            form.ResumeLayout(false);
            form.PerformLayout();

            windowService.ShowDialog(form);
            form?.Dispose();
        }
    }
}