在下拉菜单中显示 ToolStripControlHost 的图像

Show Image for ToolStripControlHost in drop down menu

我有一个 ToolStripSplitButton,下拉列表中有各种元素。 其中之一是包含在 ToolStripControlHost 中的 Trackbar,称为 ToolStripTrackbarItem。它是代码(我从 Whosebug 得到它):

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;

namespace Application
{
    [System.ComponentModel.DesignerCategory("code")]
    [System.Windows.Forms.Design.ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ContextMenuStrip | ToolStripItemDesignerAvailability.MenuStrip)]

    public class ToolStripTrackbarItem : ToolStripControlHost
    {
        public ToolStripTrackbarItem()
            : base(CreateControlInstance())
        {
            this.Size = Control.Size;
        }
        public TrackBar TrackBar
        {
            get { return Control as TrackBar; }
        }
        private static Control CreateControlInstance()
        {
            TrackBar t = new TrackBar();
            t.AutoSize = false;
            return t;
        }
        [DefaultValue(0)]
        public int Value
        {
            get { return TrackBar.Value; }
            set { TrackBar.Value = value; }
        }
        protected override void OnSubscribeControlEvents(Control control)
        {
            base.OnSubscribeControlEvents(control);
            TrackBar trackBar = control as TrackBar;
            trackBar.ValueChanged += new EventHandler(trackBar_ValueChanged);
        }
        protected override void OnUnsubscribeControlEvents(Control control)
        {
            base.OnUnsubscribeControlEvents(control);
            TrackBar trackBar = control as TrackBar;
            trackBar.ValueChanged -= new EventHandler(trackBar_ValueChanged);
        }
        void trackBar_ValueChanged(object sender, EventArgs e)
        {
            if (this.ValueChanged != null)
                ValueChanged(sender, e);
        }
        public event EventHandler ValueChanged;
        protected override Size DefaultSize
        {
            get { return new Size(300, 16); }
        }
    }

有效,但我需要在下拉项的左侧显示图像:

我通过设置图像 属性 成功地使用了一个简单的 ToolStripMenuItem。但是,设置我的 ToolStripTrackbarItem(继承自 ToolStripControlHost,请参见上面的代码)的 Image 属性 是无效的。根据 MSDN,Image 属性 与 ToolStripControlHost 无关。

这是什么意思?甚至不能包含留给 ToolStripControlHost 的图像吗?

如果可以的话,怎么做?

你应该在这里解决 2 个问题:

  • ToolStripControlHost 不显示 Image 属性 并且在保存表单时也不序列化图像。
  • ToolStripProfessionalRendered 不为 ToolStripControlHost 绘制图像。

您需要覆盖 ToolStripControlHostImage 属性 并使其可浏览和序列化。您还需要创建自定义渲染器以在正确的位置和大小绘制图像。然后,如果您使用以下代码简单地为 ToolStrip 设置渲染器,您将获得预期的结果:

this.toolStrip1.Renderer = new MyCustomRenderer();

ToolStripTrackBar

该项目使 Image 属性 显示在 属性 网格中,并在保存表格时让它序列化。

using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripTrackBar : ToolStripControlHost
{
    public TrackBar TrackBar { get { return (TrackBar)Control; } }
    public ToolStripTrackBar() : base(CreateControl()) { }
    private static TrackBar CreateControl()
    {
        var t = new TrackBar()
        { TickStyle = TickStyle.None, AutoSize = false, Height = 28 };
        return t;
    }
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public override Image Image
    {
        get { return base.Image; }
        set { base.Image = value; }
    }
    /*Expose properties and events which you need.*/
    public int Value
    {
        get { return TrackBar.Value; }
        set { TrackBar.Value = value; }
    }
}

MyCustomRenderer

此渲染器为 ToolStripTrackBar 绘制图像。

using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class MyCustomRenderer : ToolStripProfessionalRenderer
{
    protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
    {
        base.OnRenderImageMargin(e);
        e.ToolStrip.Items.OfType<ToolStripTrackBar>()
         .ToList().ForEach(item =>
         {
             if (item.Image != null)
             {
                 var size = item.GetCurrentParent().ImageScalingSize;
                 var location = item.Bounds.Location;
                 location = new Point(5, location.Y + 1);
                 var imageRectangle = new Rectangle(location, size);
                 e.Graphics.DrawImage(item.Image, imageRectangle,
                     new Rectangle(Point.Empty, item.Image.Size),
                     GraphicsUnit.Pixel);
             }
         });
    }
}