User control with auto-height property

被刻印的时光 ゝ 提交于 2019-12-01 11:36:40

Here is an auto-height control. If you change the width of control, the height of control will changes in way which the whole text can be shown.

You can create such control using different approaches including:

  • Approach 1: Auto-size Composite Control hosting a Label
    This approach is based on hosting an auto-size Label with dynamic maximum width in an auto-size Control. In this approach we set maximum width of label based on width of control and since the label is auto-size, its height will be automatically set to show all texts and then we set height of control based on height of label.

  • Approach 2: Auto-Size Simple Control from scratch without Label
    This approach is based on overriding SetBoundsCore and setting size of control based on its Text size. In this approach we calculate the size of text based on width of control using TextRenderer.MeasureText and then set calculated height as height of control. In this approach you should handle text format flags and rendering yourself.

In both approaches a ControlDesigner is used to disable all size grab handles except left and right.

Please note

These are not the only approaches available but are good examples. As another option you can inherit from a Label and change it's behavior.

Approach 1: Auto-size Composite Control hosting a Label

It works based on setting AutoSize property of label to true and then setting MaximumSize of label based on contol Width. Also the height of control is set based on height of label. You can simply draw the image in OnPaint method. Also you can add a PictureBox for image.

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
[Designer(typeof(MyLabelDesigner))]
public partial class MyLabel : Control
{
    public MyLabel() { InitializeComponent(); }
    private System.Windows.Forms.Label textLabel;
    private void InitializeComponent()
    {
        this.textLabel = new System.Windows.Forms.Label();
        this.textLabel.AutoSize = true;
        this.textLabel.Location = new System.Drawing.Point(0, 0);
        this.textLabel.Name = "label1";
        textLabel.SizeChanged += new EventHandler(textLabel_SizeChanged);
        this.AutoSize = true;
        this.Controls.Add(this.textLabel);
    }
    void textLabel_SizeChanged(object sender, EventArgs e)
    {
        this.Height = this.textLabel.Bottom + 0;
    }
    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        this.textLabel.MaximumSize = new Size(this.Width, 0);
    }
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public override string Text
    {
        get { return this.textLabel.Text; }
        set { this.textLabel.Text = value; }
    }
}

Approach 2: Auto-Size Simple Control from scratch without Label

This approach works based on setting size of control in SetBoundsCore based on current width and calculated height of its Text. To calculate height of control. You can simply draw the Image.

using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms.Design;
[Designer(typeof(MyLabelDesigner))]
public class ExLabel : Control
{
    public ExLabel()
    {
        AutoSize = true;
        DoubleBuffered = true;
        SetStyle(ControlStyles.ResizeRedraw, true);
    }
    protected override void OnTextChanged(System.EventArgs e)
    {
        base.OnTextChanged(e);
        SetBoundsCore(Left, Top, Width, Height, BoundsSpecified.Size);
        Invalidate();
    }
    protected override void SetBoundsCore(int x, int y, int width, int height,
        BoundsSpecified specified)
    {
        var flags = TextFormatFlags.Left | TextFormatFlags.WordBreak;
        var proposedSize = new Size(width, int.MaxValue);
        var size = TextRenderer.MeasureText(Text, Font, proposedSize, flags);
        height = size.Height;
        base.SetBoundsCore(x, y, width, height, specified);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var flags = TextFormatFlags.Left | TextFormatFlags.WordBreak;
        TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle,
            ForeColor, BackColor, flags);
    }
}

Designer

Here is the ControlDesigner which used to limit size grab handles in designer to left and right for both implementations:

using System.Windows.Forms.Design;
public class MyLabelDesigner : ControlDesigner
{
    public override SelectionRules SelectionRules
    {
        get
        {
            return (base.SelectionRules & ~(SelectionRules.BottomSizeable | 
                                            SelectionRules.TopSizeable));
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!