Search code examples
c#winformslabelownerdrawn

Label UserPaint drawn text doesn't fit


I have a custom Label class, drawn text doesn't fits. What am I doing wrong here?

class MyLabel: Label
{
    public MyLabel()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, Color.Black, Color.LightGray, LinearGradientMode.ForwardDiagonal))
            e.Graphics.DrawString(Text, Font, brush, ClientRectangle);
    }
}

If I set text of MyLabel to be "123456790 123456790" (AutoSize = true), then I see in Designer (or at run-time) "1234567890 123456789 " (no last zero, but some space). If I try "1234567890 1234567890 1234567890 1234567890", then there will be "1234567890 1234567890 1234567890 12345678 " (no "90", but again some space).


Solution

  • Here goes a solution (possible not the best one) to the described problem which can be rephrased as "Autosized Label with Graditent text color".

    class MyLabel: Label
    {
        private bool _autoSize = true;
        /// <summary>
        /// Get or set auto size
        /// </summary>
        public new bool AutoSize
        {
            get { return _autoSize; }
            set
            {
                _autoSize = value;
                Invalidate();
            }
        }
    
        public MyLabel()
        {
            SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
            base.AutoSize = false;
        }
    
        protected override void OnPaint(PaintEventArgs e)
        {
            // auto size
            if (_autoSize)
            {
                SizeF size = e.Graphics.MeasureString(Text, Font);
                if (ClientSize.Width < (int)size.Width + 1 || ClientSize.Width > (int)size.Width + 1 ||
                ClientSize.Height < (int)size.Height + 1 || ClientSize.Height > (int)size.Height + 1)
                {
                    // need resizing
                    ClientSize = new Size((int)size.Width + 1, (int)size.Height + 1);
                    return;
                }
            }
            using (LinearGradientBrush brush = new LinearGradientBrush(ClientRectangle, Color.Black, Color.LightGray, LinearGradientMode.ForwardDiagonal))
            e.Graphics.DrawString(Text, Font, brush, ClientRectangle);
        }
    }
    

    Idea behind is very simple: override AutoSize and process it within Paint event (everything in one place), if required size of text is different from ClientSize - resize control (which will cause redraw). One thing is what you have to add +1 to the width and height because SizeF have fractions and it's better to have +1 pixel more than loose 1 pixel sometimes and have your text not fitting.