winforms 如何在ContextMenuStrip中为ToolStripMenuItems设置可变高度?

rvpgvaaj  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(99)

我需要有多行项目,但每隔一个项目的高度成为多行相同。我不知道如何控制它的高度。在下面的图片中,其他3个项目与第一个项目具有相同的高度,但它们可以更小。我在ToolStripmenuItem中看到一个AutoSize属性,但我不知道需要使用哪个事件来计算它的高度。

afdcj2ne

afdcj2ne1#

一个示例,使用一个泛型类处理标准ToolStripProfessionalRenderer对象并重写其OnRenderItemText()方法以提供MenuItem的自定义计算大小。
当然,您可以 * 注入 * 自己的ToolStripProfessionalRenderer,也可以提供自定义的ProfessionalColorTable,以定义ToolStrip(或派生类,如ContextMenuStrip)及其MenuItem的所有颜色
这里有一个例子(用稍微不同的语言编码,但注解和一般描述仍然适用):Change space between Image and Text in ContextMenuStrip
要使ContextMenuStrip使用此自定义渲染器,请使用ToolStripRenderer派生对象(此处为标准ToolStripProfessionalRenderer)进行初始化,并设置其对应的Property:

var renderer = new MenuDesignerRendererTextWrap<ToolStripProfessionalRenderer>();
[ContextMenuStrip].Renderer = renderer;

注意事项

我建议在代码中设置MenuItems的文本,当这个文本应该换行时。
您可以插入换行符(\r\n\r\n中的任何一个都可以)将文本分为两行或多行。
这在设计师中很难做到。ContextMenuStrip和MenuItems都自动调整其大小作为默认行为。实际上,您还希望ContextMenuStrip自动调整大小为子MenuItem的总高度,否则您必须自己完成此操作。
此外,Item文本的默认呈现使用TextRenderer将文本呈现到Bitmap上。其中一个直接的影响是换行不起作用,因此在设计器中设置一个长字符串不会导致渲染器将其绘制在多行中(无论您是否尝试强制它,设置自定义TextFormatFlags)。
你可以自己使用Graphics.DrawString(),在基类代码中绕过TextRenderer,但是渲染是不同的(另外,除了这篇文章的范围:)
如前所述,在代码中设置MenuItem的文本更简单,强制换行(这里只有\n):

[ToolStripMenuItem].Text = "Some text\nMore text in a new line";
internal class MenuDesignerRendererTextWrap<T> : ToolStripProfessionalRenderer where T :
        ToolStripRenderer, new() {
    public MenuDesignerRendererTextWrap() : this(new T()) { }

    public MenuDesignerRendererTextWrap(T renderer) => Renderer = renderer;

    public T Renderer { get; }

    private readonly TextFormatFlags flags = 
        TextFormatFlags.LeftAndRightPadding | TextFormatFlags.VerticalCenter;

    protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) {
        if (string.IsNullOrEmpty(e.Text)) return;
        
        // The size of the Item is provided here
        e.Item.AutoSize = false;

        // An Item's viewport is 3 pixels higher than the text's Height
        var textHeight = TextRenderer.MeasureText(
            e.Graphics, e.Text, e.TextFont, 
            new Size(e.TextRectangle.Width, int.MaxValue), flags).Height + 3;
        var textRect = new Rectangle(
            e.TextRectangle.Left, e.TextRectangle.Top, e.TextRectangle.Width, textHeight);

        // Bounds of the Item's text
        e.TextRectangle = textRect;
        // Overall height of the MenuItem: text's viewport.Height + 3 pixels
        e.Item.Height = textHeight + 3;

        base.OnRenderItemText(e);
    }
}

相关问题