具有自动高度属性的用户控件 [英] User control with auto-height property

查看:78
本文介绍了具有自动高度属性的用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建将显示文本的用户控件。

我需要一种在运行时调整控件大小的方法,以便它可以调整高度以显示所有文本。
我创建了如下所示的控件:

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 control that looks like this:

如您所见,我有使用 TextRenderer.DrawText 绘制的图标和文本。不幸的是,当我调整控件大小(仅向左或向右)时,有时会剪切文本,如下所示:

As You can see I have icon and text drawn using TextRenderer.DrawText. Unfortunately when I resize my control (only to left or right) my text is sometimes cut, ass shown below:

我正在使用 TextRenderer.MeasureText 测量文本,基于这一点,我计算行数,然后正在绘制该文本。这是我正在使用的代码:

I'm measuring text using TextRenderer.MeasureText based on that I'm counting number of lines and then I'm drawing that text. Here is code I'm using:

[Designer(typeof(MyTextBoxDesigner))]
public partial class MyTextBox : UserControl
{
    public MyTextBox()
    {
        InitializeComponent();
    }

    [DefaultValue("Demo"), Description("Text of control"), Category("Appearance"),Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public override string Text
    {
        get
        {
            return base.Text;
        }
        set
        {
            if (base.Text == value) return;
            base.Text = value;
            Invalidate();
        }
    }

    Image _image;
    [Description("Image shown on the left side of the control"),
    Category("Appearance")]
    public Image Image
    {
        get
        {
            return _image;
        }
        set
        {
            if (_image == value) return;
            _image = value;
            Invalidate();
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        int imagePadding = 0;
        if (_image != null)
        {
            imagePadding = 25;
            e.Graphics.DrawImage(_image,new Rectangle(5,5,16,16));
        }
        Size textSize1 = TextRenderer.MeasureText(e.Graphics, Text, Font);
        SizeF textSize2 = e.Graphics.MeasureString(Text, Font);

        Debug.WriteLine(textSize2);

        int maxTextWidth = Width - Padding.Left-Padding.Right-imagePadding;
        int lineHeight = textSize1.Height + 2;
        int numLines = 1;

        if (textSize1.Width > maxTextWidth)
        {
            numLines = textSize1.Width / maxTextWidth + 1;
        }

        Rectangle textRect = new Rectangle
        {
            Width = Width - Padding.Left-Padding.Right-imagePadding,
            Height = (numLines * lineHeight),
            X = Padding.Left+imagePadding,
            Y = 5
        };

        TextRenderer.DrawText(e.Graphics, Text, Font, textRect, ForeColor, TextFormatFlags.WordBreak | TextFormatFlags.Left | TextFormatFlags.Top);

        e.Graphics.DrawRectangle(Pens.CadetBlue, textRect);

        base.OnPaint(e);
    }
}

internal class MyTextBoxDesigner : ControlDesigner
{
    public override SelectionRules SelectionRules
    {
        get
        {
            //all minus bottom and top
            return (base.SelectionRules & ~(SelectionRules.BottomSizeable | SelectionRules.TopSizeable));
        }
    }
}

理想情况下,我想控件可根据文本长度自动调整高度,因此,如果文本较短(或控件足够长),则in的高度例如为20px,但是如果文本较长,则我的控件应为(例如)40px高度(2行文本) )。

Ideally I'd like my control to auto-adjust height based on text length, so if text is short (or control long enough) in will be for example 20px height, but if text is long my control should be (for example) 40px height (2 lines of text).

如何更改文本尺寸以正确计算 textRect

我应该使用Size属性更新控件的高度还是有更好的方法?

How should I change my text measurement to calculate textRect correctly?
Should I update height of my control using Size property or is there a better way?

编辑:
基本上我想绘制可以包裹在矩形内但宽度固定的文本,因此当文本较长时,该矩形将调整其高度。然后根据该高度调整控件的高度。

Basically I want to draw text that can wrap inside rectangle, but has fixed width, so when text is longer that rectangle will adjust its height. Then based on that height I want to adjust control height.

推荐答案

这是一个自动高度控件。如果更改控件的宽度,控件的高度将以可显示整个文本的方式更改。

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:


  • 方法1:托管标签的自动调整大小的复合控件

    此方法基于在自动大小控件中托管具有动态最大宽度的自动大小 Label 。在这种方法中,我们根据控件的宽度设置标签的最大宽度,并且由于标签是自动调整大小的,因此标签的高度将自动设置为显示所有文本,然后我们根据标签的高度设置控件的高度。

  • 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.

方法2:从头开始自动调整大小,无需标签

这种方法基于覆盖 SetBoundsCore 并根据其 Text 大小设置控件的大小。在这种方法中,我们使用 TextRenderer.MeasureText ,然后将计算出的高度设置为控件的高度。在这种方法中,您应该处理文本格式标志并呈现自己。

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.

在两种方法中, ControlDesigner 用于禁用除左侧和右侧之外的所有尺寸的抓取手柄。

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

请注意

这些不是可用的唯一方法,而是很好的例子。另一种选择是,您可以从 Label 继承并更改其行为。

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.

它基于将标签的 AutoSize 属性设置为 true ,然后基于contol Width 设置标签的 MaximumSize 。控件的高度也根据标签的高度设置。
您可以简单地使用 OnPaint 方法绘制图像。也可以为图像添加 PictureBox

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



方法2:自动调整大小从头开始没有标签的控件



此方法基于在 SetBoundsCore 中设置控件的大小而工作文本的当前宽度和计算出的高度。计算控件的高度。您只需使用System.Windows.Forms绘制 Image

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



设计师



这是 ControlDesigner ,用于在两种实现方式中将设计器中的大小抓取手柄限制为左右:

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

这篇关于具有自动高度属性的用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆