2016-06-21 143 views
3

我試圖創建一個繼承NumericUpDown以顯示可設置單位的自定義控件。自定義控件|字段填充

這是(視覺)我有這麼遠:

enter image description here

我的代碼:看起來有點長,但是,這不是做那麼多

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

我的問題:

該標籤目前覆蓋框的結尾。所以,如果一個大的價值來自於(或大小爲低)它得到由標籤覆蓋,出現在這裏:

enter image description here

我知道NumericUpDown有類似滾動功能時,在輸入值比輸入框的大小更長。這是在框的結尾觸發的。

是否以任何方式設置類似填充爲框內文本的可能性?例如,將右側的填充設置爲我的標籤的大小?

我很喜歡這個自定義控件,但是這最後一件事很煩人。


不幸的是我不知道如何查找現有控件的屬性,例如有一個名爲UpdateEditText()方法。也許有人可以告訴我如何查找這個基本功能/屬性。

非常感謝!

+0

您可以免費獲得「滾動」功能,但它僅適用於控件呈現的文本。你只是在特定的點上疊加一個'Label'。我認爲你真的想嘗試將完整的文本提供給控件,而不是自己繪製任何文本。這可能意味着你已經管理文本和值,因爲文本將是非數字的。 – DonBoitnott

+0

@DonBoitnott這是我第一個想法。但後來我意識到我已經用我的小數點修正來抓取文本。因此,將這些主題分開並不會那麼糟糕(例如使用標籤)。接受的答案在這裏很有效。 – C4u

回答

2

NumericUpDown是繼承自UpDownBase組合控件的控件。它包含一個UpDownEdit和一個UpDownButtons控件。 UpDownEditTextBox。您可以更改控件及其子項的外觀。

enter image description here

代碼

:例如,你可以一個 Label添加到文本框控件,並將其停靠的 TextBox權,然後通過發送 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); 
    } 
} 
+0

工作很棒!你介意告訴我你是如何創建這個gif的?我不認爲你花了1個小時。相關主題:很傷心沒有'EC_LEFTMARGIN'。有了這個,我可以創建一個新的屬性'UnitDock'。 – C4u

+2

** - **我使用[ScreenToGif](https://screentogif.codeplex.com/)記錄屏幕的選定區域並將其保存爲動畫gif。 ** - **要設置左邊距,請定義'private const int EC_LEFTMARGIN = 1;'然後'SendMessage(控件[1] .Handle,EM_SETMARGINS,EC_LEFTMARGIN,label.Width);' –

+0

哇,謝謝您的回答! – C4u