c# - ToolStripLayoutStyle.Table 在 ContextMenuStrip 中不起作用

标签 c# .net winforms contextmenustrip

我想显示一个上下文菜单,其中菜单项是排列在网格中的图像。但是,当我在菜单的 ToolStripDropDown 中将 LayoutStyle 设置为 ToolStripLayoutStyle.Table 时,如果创建了新的 ToolStripDropDown 对象,它只会提供菜单项的网格布局。

我的问题是我可以为子菜单创建并分配一个新的 ToolStripDropDown,但不能为 ContextMenuStrip 创建和分配一个新的 ToolStripDropDown,因为它是 ToolStripDropDown。

以下代码演示了该问题。它将显示一个包含颜色样本图像的上下文菜单,并且还有两个具有相同图像的子菜单。所有三个菜单的 LayoutStyle 属性均设置为 ToolStripLayoutStyle.Table,但只有一个菜单实际上会显示为网格。

private void FillDropDown(ToolStripDropDown drop_down)
{
    // Set the drop down to a 2 column table layout
    drop_down.LayoutStyle = ToolStripLayoutStyle.Table;
    TableLayoutSettings table_layout_settings = (TableLayoutSettings)drop_down.LayoutSettings;
    table_layout_settings.ColumnCount = 2;

    // Fill the menu with some colour swatches
    Color[] colours = { Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Purple };
    foreach (Color colour in colours) {
        ToolStripMenuItem item = new ToolStripMenuItem();
        Bitmap swatch = new Bitmap(64, 64);
        using (Graphics g = Graphics.FromImage(swatch))
        using (SolidBrush b = new SolidBrush(colour)) {
            g.FillRectangle(b, 0, 0, 64, 64);
        }
        item.Image = swatch;
        item.DisplayStyle = ToolStripItemDisplayStyle.Image;
        item.Margin = new Padding(2, 2, 2, 2);
        drop_down.Items.Add(item);
    }
}

private void ShowColorMenu(Point screen_location)
{
    ContextMenuStrip context_menu = new ContextMenuStrip();

    // The root context menu will not layout as a grid
    FillDropDown(context_menu);

    // This sub-menu will not layout as a grid
    ToolStripMenuItem sub_menu = new ToolStripMenuItem("Sub-menu");
    FillDropDown(sub_menu.DropDown);
    context_menu.Items.Add(sub_menu);

    // A sub-menu will layout as a grid if we create a new ToolStripDropDown for it
    ToolStripMenuItem grid_sub_menu = new ToolStripMenuItem("Grid Sub-menu");
    ToolStripDropDown new_drop_down = new ToolStripDropDown();
    FillDropDown(new_drop_down);
    grid_sub_menu.DropDown = new_drop_down;
    context_menu.Items.Add(grid_sub_menu);

    context_menu.Show(screen_location);
}

在我的机器上结果如下:

Context menu showing grid layout in sub-menu and linear layout in root menu

我想在上下文菜单的根目录中有一个图像网格。理解它为什么会这样也很好。我已经浏览了 .NET 引用源,但这一次没有帮助。

最佳答案

ContextMenuStrip由于菜单呈现/布局的限制,无法在表格布局中显示其 ToolStripMenuItems,并且您也无法将 ContextMenuStrip 强制转换为 ToolStripDropDown (或者反过来;它是 ToolStripDropDownMenu 周围的包装,它不能转换为其间接祖先:它将保留其特定功能(例如,您可以< em>将 TextBox 和 ListBox 都视为 Control,但这并不意味着现在设置 ListBox 的 Text 实际上会在某处显示文本,只是因为 Text属性属于 Control 类)。

但是您可以像 ContextMenuStrip 一样直接使用和显示 ToolStripDropDown。 ToolStripDropDown 的 LayoutSettings可以直接转换到TableLayoutSettings和一个LayoutStyle类型 ToolStripLayoutStyle.Table完全支持。


在示例中,包含排列在表格布局中的 ToolStripMenuItems 的 ToolStripDropDown 对象用作 ContextMenuStrip,以选择要应用于 PictureBox 控件的彩色图像,而颜色名称显示在 Label 控件中。

ToolStripDropDown as ContextMenuStrip

下拉菜单在表单初始化时创建,在表单的 ClientArea 内单击鼠标右键时显示​​,并在表单关闭时释放:

注意1:在这里,我使用 Lambda 订阅 ToolStripDropDown.ItemClicked 事件。然而,对于这种类型的控件,最好使用方法委托(delegate)。

注意2:ToolStripDropDown 是通过调用contextColorMenu.Dispose(); 来处理的。如果容器 Form 频繁打开和关闭,最好显式处置 ToolStripMenuItems Images。

using System.Drawing;
using System.Windows.Forms;

public partial class SomeForm : Form
{
    private ToolStripDropDown contextColorMenu = null;

    public SomeForm()
    {
        InitializeComponent();
        contextColorMenu = new ToolStripDropDown();
        contextColorMenu.ItemClicked += (o, a) => {
            // Assign the selected Bitmap to a PitureBox.Image
            picColor.Image = a.ClickedItem.Image;
            // Show the Color description in a Label
            lblColor.Text = ((Color)a.ClickedItem.Tag).ToString();
        };
        FillDropDown(contextColorMenu);
    }
    
    private void ShowColorMenu(Point location) => contextColorMenu.Show(location);

    private void FillDropDown(ToolStripDropDown dropDown)
    {
        dropDown.LayoutStyle = ToolStripLayoutStyle.Table;
        (dropDown.LayoutSettings as TableLayoutSettings).ColumnCount = 2;
        (dropDown.LayoutSettings as TableLayoutSettings).GrowStyle = TableLayoutPanelGrowStyle.AddRows;

        Color[] colors = { Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Purple };

        foreach (Color color in colors) {
            var swatch = new Bitmap(64, 64);
            using (var g = Graphics.FromImage(swatch)) {
                g.Clear(color);
            }
            var item = new ToolStripMenuItem() {
                DisplayStyle = ToolStripItemDisplayStyle.Image,
                Image = swatch,
                Tag = color,
                Margin = new Padding(2),
                Padding = new Padding(2, 1, 2, 1)  // Fine tune the Items' Cell border
            };
            dropDown.Items.Add(item);
        }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        if (e.Button == MouseButtons.Right) {
            ShowColorMenu(MousePosition);
        }
    }

    protected override void OnFormClosed(FormClosedEventArgs e)
    {
        base.OnFormClosed(e);
        contextColorMenu?.Dispose();
    }
}

关于c# - ToolStripLayoutStyle.Table 在 ContextMenuStrip 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62549612/

相关文章:

c# - Instagram OAuth GetExternalLoginInfoAsync 在 .NET Core 2.0 中始终返回 null

c# - 我看到的是真正的内存泄漏吗?

c# - 读取文件特定行号的有效方法。 (奖金 : Python Manual Misprint)

c# - 图片框 图片框

c# - 如何防止存储过程错误在 SqlClient 中抛出异常?

c# - 在哪里放置验证逻辑?在服务或存储库中?

c# - SslStream.AuthenticateAsClient - 发送时无法立即完成非阻塞套接字操作

c# - 如何在 Linq 中将字符串列与数字(作为小数)进行比较

c# - 如何更改 Windows 窗体标题栏中的文本?

c# - 让 ActiveX 控件在没有窗体的情况下工作?