User control with auto-height property

前端 未结 1 1848
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-15 14:43

I want to create user control that will display text.
I need a way to resize control at run-time so that it will adjust height to show all the text. I\'ve created contro

1条回答
  •  隐瞒了意图╮
    2021-01-15 15:21

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

    0 讨论(0)
提交回复
热议问题