简体   繁体   中英

How to give padding(all sides) to a value inside NumericUpDown Control in Winforms

I am stuck with this problem of giving padding to all sides to a value inside NumericUpDown control in Winforms.

Apparently no one has asked this before.

Actual how control is looking: ( https://i.stack.imgur.com/KIweV.png ) Expected how I want control to look: enter image description here

Ignore other differences in both the attached images. Just need to pad the value from top, bottom and left; as part of this question.

So far, I have only figured out that there is a TextAlign property which can align either Left or Right or Center, but that doesn't help in giving padding to top and bottom edges of the control.

Below code is not solving my problem this.numericUpDown1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;

AFAIK, you can't control the height of a winforms NumericUpDown control, and therefor it's text-aling property only allows left, center, and right (as opposed to, say, a label which has 9 possibilities (TopLeft, MiddleCenter, BottomRight and so on).
You can, however, create your own control to replace the built in numericUpDown, but that's going to take a lot of work.
Perhaps someone have already done this work and released an open source somewhere.

The NumericUpDown control has an internal UpDownEdit child derives from the TextBox control used to display and edit the value. You can p/invoke to set the Left and/or the Right margins of a single-line TextBox . Add to that the Top and/or Bottom margins of a multiline TextBox .

Consider the listed extension class which targets the derived types from the TextBoxBase abstract class. It adds the SetInnerMargin method to these types to set the inner margins. Note, for the single-line text boxes, the values of the Top and Bottom properties of the Padding struct are ignored.

// TextBox, RichTextBox...etc.
public static class TextBoxBaseExtensions
{
    private const int EM_SETRECT = 0xB3;
    private const int EM_SETMARGINS = 0xD3;

    private const int EC_LEFTMARGIN = 0x1;
    private const int EC_RIGHTMARGIN = 0x2;

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left, Top, Right, Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            Left = left;
            Top = top;
            Right = right;
            Bottom = bottom;
        }

        public RECT(Rectangle r)
        {
            Left = r.Left;
            Top = r.Top;
            Right = r.Right;
            Bottom = r.Bottom;
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref RECT rect);

    public static void SetInnerMargin(this TextBoxBase self, Padding pad)
    {
        if (self.Multiline)
        {
            var r = new Rectangle(
                pad.Left, 
                pad.Top, 
                self.ClientSize.Width - pad.Left - pad.Right, 
                self.ClientSize.Height - pad.Top - pad.Bottom);
            var nr = new RECT(r);

            SendMessage(self.Handle, EM_SETRECT, 0, ref nr);
        }
        else
        {
            SendMessage(
                self.Handle,
                EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
                pad.Right * 0x10000 + pad.Left);
        }
    }
}

Usage examples:

var pad = new Padding(5);

textBox1.SetInnerMargin(pad);
richTextBox1.SetInnerMargin(pad);
(numericUpDown1.Controls[1] as TextBox).SetInnerMargin(pad);

Make sure that the handles of the target controls are created and assigned before you call this method. Alternatively, subscribe to their HandleCreated events to call it.

Also, you can create custom controls to implement this feature. For example:

public class NumericUpDownEx : NumericUpDown
{
    private Padding inMargin = Padding.Empty;
    /// <summary>
    /// Gets or sets the inner margins. The Left and Right only.
    /// The Top and Bottom margins are ignored.
    /// </summary>
    [DefaultValue(typeof(Padding), "0, 0, 0, 0")]
    public Padding InnerMargin
    {
        get => inMargin;
        set
        {
            if (inMargin != value)
            {
                inMargin = value;
                SetInnerMargins();
            }
        }
    }

    /// <inheritdoc cref="TextBox.TextAlign"/>
    new public HorizontalAlignment TextAlign
    {
        get => base.TextAlign;
        set
        {
            if (base.TextAlign != value)
            {
                base.TextAlign = value;
                SetInnerMargins();
            }
        }
    }

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        SetInnerMargins();
    }

    private void SetInnerMargins()
    {
        if (Controls[1] is TextBox tb)
            tb.SetInnerMargin(InnerMargin);
    }
}

SO74470685

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM