Feri
Feri

Reputation: 501

Show Image for ToolStripControlHost in drop down menu

I have a ToolStripSplitButton with various elements in dropdown list. One of them is a Trackbar enclosed in a ToolStripControlHost, called ToolStripTrackbarItem. It's code (I've got it from stackoverflow):

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); }
        }
    }

It works, but I need to show images to the left of the dropdown items:

menu

I'm successful with a simple ToolStripMenuItem by setting the Image property. However, it is ineffective to set Image property of my ToolStripTrackbarItem (that is inherited from ToolStripControlHost, see code above). According to MSDN, Image property is irrelevant to ToolStripControlHost.

What does it mean? Is it not even possible to include an image left to ToolStripControlHost?

If it is possible anyway, how to do that?

Upvotes: 3

Views: 1265

Answers (1)

Reza Aghaei
Reza Aghaei

Reputation: 125187

You should solve 2 problems here:

  • ToolStripControlHost doesn't show Image property and also doesn't serialize the image when you save the form.
  • ToolStripProfessionalRendered doesn't draw image for ToolStripControlHost.

You need to override Image property of ToolStripControlHost and make it browsable and serializable. Also you need to create a custom renderer to draw the image in the correct location and size. Then if you simply set the renderer for ToolStrip using below code, you will get expected result:

this.toolStrip1.Renderer = new MyCustomRenderer();

enter image description here

ToolStripTrackBar

The item enables Image property to show in property grid and let it serialize when saving form.

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

This renderer draws images for 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);
             }
         });
    }
}

Upvotes: 5

Related Questions