How to render graphics on ToolStrip

156 Views Asked by At

I have created a custom user control that will display text and an indicator light to display the current running status of our service as shown in the form below. It works just fine on a form, but I want to put it on a StatusStrip control. I created a class derived from ToolStripControlHost to enable support for my control on a StatusStrip, but it doesn't render at all. The width of the control is zero and the form flickers while open in the IDE.

I have looked at the ToolStripRendering class, but it would appear to me that it is intended to be used with existing supported controls.

What's the best way to achieve this? If even possible? My Code is below.

I'm using Visual Studio 2010 with .NET 4.0

enter image description here

User Control Code:

public partial class ServiceStatus : UserControl
{
    public ServiceStatus()
    {
        IndicatorSize = new System.Drawing.Size(20, 20);
        Padding = new Padding(1, 1, 1, 1);
        InitializeComponent();
    }

    public ServiceControllerStatus GetStatus()
    {
        using (var service = new ServiceController("MyService"))
        {
            return service.Status;
        }
    }
    private void getStatusInfo(out string statusText, out Color indicatorColor)
    {
        try
        {
            ServiceControllerStatus status = GetStatus();
            switch (status)
            {
                case ServiceControllerStatus.ContinuePending:
                    statusText = Properties.Resources.SERVICE_CONTINUE_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Paused:
                    statusText = Properties.Resources.SERVICE_PAUSED;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.PausePending:
                    statusText = Properties.Resources.SERVICE_PAUSE_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Running:
                    statusText = Properties.Resources.SERVICE_RUNNING;
                    indicatorColor = Color.Green;
                    break;
                case ServiceControllerStatus.StartPending:
                    statusText = Properties.Resources.SERVICE_START_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Stopped:
                    statusText = Properties.Resources.SERVICE_STOPPED;
                    indicatorColor = Color.Red;
                    break;
                case ServiceControllerStatus.StopPending:
                    statusText = Properties.Resources.SERVICE_STOP_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                default:
                    statusText = default(String);
                    indicatorColor = default(Color);
                    break;
            }
        }
        catch
        {
            statusText = Properties.Resources.SERVICE_CANNOT_CONNECT;
            indicatorColor = Color.Red;
        }
    }

    public Size IndicatorSize { get; set; }


    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        string statusText;
        Color indicatorColor;

        getStatusInfo(out statusText, out indicatorColor);

        Size textSize = TextRenderer.MeasureText(e.Graphics, statusText, Font, new Size(int.MaxValue, int.MinValue), TextFormatFlags.NoPadding);
        this.Size = new Size(Padding.Left + textSize.Width + 5 + IndicatorSize.Width + Padding.Right,
                               Padding.Top + Math.Max(textSize.Height, IndicatorSize.Height) + Padding.Bottom);
        Point textStart = new Point(Padding.Left, (this.Size.Height-textSize.Height) / 2);
        Rectangle textBounds = new Rectangle(textStart, textSize) ;
        Brush indicatorBrush = new SolidBrush(indicatorColor) ;
        Point indicatorStart = new Point(textStart.X + textSize.Width + 5, (this.Size.Height-IndicatorSize.Height) / 2) ;
        Rectangle indicatorBounds = new Rectangle(indicatorStart, IndicatorSize) ;

        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        TextRenderer.DrawText(e.Graphics, statusText, Font, textBounds, ForeColor, TextFormatFlags.NoPadding);
        e.Graphics.FillEllipse(indicatorBrush, indicatorBounds);
    }
}

Tool Strip Control Host Code:

[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripServiceStatus : ToolStripControlHost
{
    public ToolStripServiceStatus()
        : base(new ServiceStatus())
    {
    }
}
1

There are 1 best solutions below

0
On BEST ANSWER

I was overthinking this. The ToolStripStatusLabel has text and image properties.

[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripServiceStatus : ToolStripStatusLabel
{
    Timer _statusRefresh = null;
    public ToolStripServiceStatus() : base()
    {
        this.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
        RefreshStatus();
    }

    void _statusRefresh_Tick(object sender, EventArgs e)
    {
        RefreshStatus();
    }

    public ServiceControllerStatus GetStatus()
    {
        using (var service = new ServiceController("MyService"))
        {
            return service.Status;
        }
    }
    public ServiceControllerStatus GetStatusInfo(out string statusText, out Color indicatorColor)
    {
        ServiceControllerStatus status = default(ServiceControllerStatus);
        try
        {
            status = GetStatus();
            switch (status)
            {
                case ServiceControllerStatus.ContinuePending:
                    statusText = Properties.Resources.SERVICE_CONTINUE_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Paused:
                    statusText = Properties.Resources.SERVICE_PAUSED;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.PausePending:
                    statusText = Properties.Resources.SERVICE_PAUSE_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Running:
                    statusText = Properties.Resources.SERVICE_RUNNING;
                    indicatorColor = Color.Green;
                    break;
                case ServiceControllerStatus.StartPending:
                    statusText = Properties.Resources.SERVICE_START_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                case ServiceControllerStatus.Stopped:
                    statusText = Properties.Resources.SERVICE_STOPPED;
                    indicatorColor = Color.Red;
                    break;
                case ServiceControllerStatus.StopPending:
                    statusText = Properties.Resources.SERVICE_STOP_PENDING;
                    indicatorColor = Color.Yellow;
                    break;
                default:
                    statusText = default(String);
                    indicatorColor = default(Color);
                    break;
            }
        }
        catch
        {
            statusText = Properties.Resources.SERVICE_CANNOT_CONNECT;
            indicatorColor = Color.Red;
        }
        return status;
    }

    string _previousStatusText = "";
    public ServiceControllerStatus RefreshStatus()
    {
        if (_statusRefresh == null)
        {
            _statusRefresh = new Timer() { Interval = 1000 };
            _statusRefresh.Tick += new EventHandler(_statusRefresh_Tick);
        }
        _statusRefresh.Enabled = false;
        string statusText;
        Color indicatorColor;
        ServiceControllerStatus status = GetStatusInfo(out statusText, out indicatorColor);

        if (_previousStatusText != statusText)
        {
            Text = statusText;
            Image bmp = new Bitmap(Height, Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                g.FillEllipse(new SolidBrush(indicatorColor), new Rectangle(0, 0, Height - 1, Height - 1));
            }
            this.Image = bmp;
        }
        _statusRefresh.Enabled = (status != ServiceControllerStatus.Stopped && status != ServiceControllerStatus.Running && status != ServiceControllerStatus.Paused);
        return status;
    }
}