带单位的 NumericUpDown |自定义控件 |字段填充

NumericUpDown with Unit | Custom control | Field padding

我正在尝试创建一个继承 NumericUpDown 的自定义控件以显示可设置的单位。

这是(视觉上)到目前为止我得到的:

我的代码: 看起来有点长,但没那么多

class NumericUpDownUnit : NumericUpDown
{
    public event EventHandler ValueChanged;

    /// <summary>
    /// Constructor creates a label
    /// </summary>
    public NumericUpDownUnit()
    {
        this.TextChanged += new EventHandler(TextChanged_Base);
        this.Maximum = 100000000000000000;
        this.DecimalPlaces = 5;

        this.Controls.Add(lblUnit);
        lblUnit.BringToFront();

        UpdateUnit();
    }

    public void TextChanged_Base(object sender, EventArgs e)
    {
        if(ValueChanged != null)
        {
            this.ValueChanged(sender, e);
        }
    }

    /// <summary>
    /// My designer property
    /// </summary>
    private Label lblUnit = new Label();
    [Description("The text to show as the unit.")]
    public string Unit
    {
        get
        {
            return this.lblUnit.Text;
        }
        set
        {
            this.lblUnit.Text = value;
            UpdateUnit();
        }
    }

    /// <summary>
    /// When unit has changed, calculate new label-size
    /// </summary>
    public void UpdateUnit()
    {
        System.Drawing.Size size = TextRenderer.MeasureText(lblUnit.Text, lblUnit.Font);
        lblUnit.Padding = new Padding(0, 0, 0, 3);
        lblUnit.Size = new System.Drawing.Size(size.Width, this.Height);
        lblUnit.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        lblUnit.BackColor = System.Drawing.Color.Transparent;
        lblUnit.Location = new System.Drawing.Point(this.Width-lblUnit.Width-17, 0);
    }

    /// <summary>
    /// If text ends with seperator, skip updating text as it would parse without decimal palces
    /// </summary>
    protected override void UpdateEditText()
    {
        if (!this.Text.EndsWith(".") && !this.Text.EndsWith(","))
        Text = Value.ToString("0." + new string('#', DecimalPlaces));
    }

    /// <summary>
    /// Culture fix
    /// </summary>
    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        if (e.KeyChar.Equals('.') || e.KeyChar.Equals(','))
        {
            e.KeyChar = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator.ToCharArray()[0];
        }
        base.OnKeyPress(e);
    }

    /// <summary>
    /// When size changes, call UpdateUnit() to recalculate the lable-size
    /// </summary>
    protected override void OnResize(EventArgs e)
    {
        UpdateUnit();
        base.OnResize(e);
    }

    /// <summary>
    /// Usability | On enter select everything
    /// </summary>
    protected override void OnEnter(EventArgs e)
    {
        this.Select(0, this.Text.Length);
        base.OnMouseEnter(e);
    }

    /// <summary>
    /// If, when leaving, text ends with a seperator, cut it out
    /// </summary>
    protected override void OnLeave(EventArgs e)
    {
        if(this.Text.EndsWith(System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator))
        {
            this.Text = this.Text.Substring(0, this.Text.Length - 1);
        }

        base.OnLeave(e);
    }
}

我的问题:

标签目前覆盖了盒子的末端。因此,如果输入的值很大(或尺寸较小),它将被标签覆盖,如下所示:

我知道 NumericUpDown 具有类似滚动功能的功能,当输入的值长于输入框的大小时。这是在框的末尾触发的。

是否有可能为框内的文本设置类似 padding 的内容?例如,将右侧的填充设置为我的标签大小?

我非常喜欢这个自定义控件,但是最后一件事很烦人。


不幸的是,我不知道如何查找现有控件的属性,例如有一个名为 UpdateEditText() 的方法。也许有人可以告诉我如何查找这个基数 functions/properties.

非常感谢!

NumericUpDown是一个继承自UpDownBase composite control. It contains an UpDownEdit and an UpDownButtons control. The UpDownEdit is a TextBox. You can change appearance of the control and its children. For example, you can add a Label to the textbox control and dock it to the right of TextBox, then set text margins of textbox by sending an EM_SETMARGINS消息的控件得到这样的结果:

代码

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class ExNumericUpDown : NumericUpDown
{
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
    private const int EM_SETMARGINS = 0xd3;
    private const int EC_RIGHTMARGIN = 2;
    private Label label;
    public ExNumericUpDown() : base()
    {
        var textBox = Controls[1];
        label = new Label() { Text = "MHz", Dock = DockStyle.Right, AutoSize = true };
        textBox.Controls.Add(label);
    }
    public string Label
    {
        get { return label.Text; }
        set { label.Text = value; if (IsHandleCreated) SetMargin(); }
    }
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        SetMargin();
    }
    private void SetMargin()
    {
        SendMessage(Controls[1].Handle, EM_SETMARGINS, EC_RIGHTMARGIN, label.Width << 16);
    }
}