2016-05-09 146 views
2

我正在創建自定義控件(水印文本框),並且它從文本框繼承。截至目前,文本框在沒有文本時正確顯示失去焦點時的水印,並在文本框獲得焦點時刪除它(即使文本的顏色是水印也會更改)。 我想要它做的是報告它沒有文字時顯示水印,所以我試圖重寫Text屬性。文本框的覆蓋文本屬性不能正確刷新

代碼如下:

public class WatermarkedTextbox : TextBox 
{ 
    private bool _isWatermarked; 
    private string _watermark; 
    public string Watermark 
    { 
     get { return _watermark; } 
     set { _watermark = value; } 
    } 


    [Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
    public override string Text 
    { 
     get 
     { 
      return _isWatermarked ? string.Empty : base.Text; 
     } 
     set 
     { 
      base.Text = value; 
     } 
    } 

    public WatermarkedTextbox() 
    { 
     GotFocus += WatermarkedTextbox_GotFocus; 
     LostFocus += WatermarkedTextbox_LostFocus; 
    } 

    private void WatermarkedTextbox_LostFocus(object sender, EventArgs e) 
    { 
     if (Text.Length == 0) 
     { 
      ForeColor = SystemColors.InactiveCaption; 
      Text = _watermark; 
      _isWatermarked = true; 
     } 
    } 

    private void WatermarkedTextbox_GotFocus(object sender, EventArgs e) 
    { 
     if (_isWatermarked) 
     { 
      ForeColor = SystemColors.ControlText; 
      Text = string.Empty; 
      _isWatermarked = false; 
     } 
    } 
} 

問題是,當文本框獲得焦點不會刪除的水印。

我在這裏錯過/做錯了什麼?

+0

可你只是做一個新的屬性,然後在文本覆蓋設置它的價值呢? – Jacobr365

+0

可能的重複[如何實現顯示「Type here」的TextBox?](http://stackoverflow.com/questions/2487104/how-do-i-implement-a-textbox-that-displays-type-這裏) – raidensan

+1

您的重寫的Text屬性獲取器也被Winforms調用。用於檢查文本框是否需要重新繪製。如果是這樣,isWatermarked字段還沒有正確的值。在文本分配前簡單地移動isWatermarked賦值*,它將起作用。 –

回答

0

Hans Passant的評論是我的問題的正確答案。此外,感謝大家花時間提供幫助。

我終於決定走最簡單的路線(處理PropertyChanged似乎太複雜,因爲這個特殊的需要和掛鉤Windows APIs留下多行文本框,所以它不是一個選項)。

萬一有人需要它,下面的代碼:

public class WatermarkedTextbox : TextBox 
{ 
    private bool _isWatermarked; 
    private string _watermark; 
    public string Watermark 
    { 
     get { return _watermark; } 
     set { _watermark = value; } 
    } 

    [Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
    public override string Text 
    { 
     get 
     { 
      return _isWatermarked ? string.Empty : base.Text; 
     } 
     set 
     { 
      base.Text = value; 
     } 
    } 

    public WatermarkedTextbox() 
    { 
     GotFocus += WatermarkedTextbox_GotFocus; 
     LostFocus += WatermarkedTextbox_LostFocus; 
    } 

    private void WatermarkedTextbox_LostFocus(object sender, EventArgs e) 
    { 
     if (Text.Length == 0) 
     { 
      _isWatermarked = true; 
      ForeColor = SystemColors.InactiveCaption; 
      Text = _watermark; 
     } 
    } 

    private void WatermarkedTextbox_GotFocus(object sender, EventArgs e) 
    { 
     if (_isWatermarked) 
     { 
      _isWatermarked = false; 
      ForeColor = SystemColors.ControlText; 
      Text = string.Empty; 
     } 
    } 
} 
0

刪除你的覆蓋文本屬性,那麼它將工作!

刪除這些行:

[Bindable(false), EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
public override string Text 
{ 
    get 
    { 
     return _isWatermarked ? string.Empty : base.Text; 
    } 
    set 
    { 
     base.Text = value; 
    } 
} 
+0

重寫Text屬性的目的是報告文本框在顯示水印時沒有文本。不這樣做會告訴每個人檢查文本框是否有有效的文本,但事實上並非如此。 –

1

啊對不起,我沒讀清楚。或者,您可能想通過重寫文本屬性來通知。

您可以使用事件本身:

public class WatermarkedTextbox : TextBox, INotifyPropertyChanged 
{ 
    private bool _isWatermarked; 
    private string _watermark; 
    public string Watermark 
    { 
     get { return _watermark; } 
     set { _watermark = value; } 
    } 

    public bool IsWaterMarked 
    { 
     get 
     { 
      return _isWatermarked; 
     } 
     set 
     { 
      _isWatermarked = value; 
      OnPropertyChanged("IsWaterMarked"); 
     } 
    } 

    public WatermarkedTextbox() 
    { 
     GotFocus += WatermarkedTextbox_GotFocus; 
     LostFocus += WatermarkedTextbox_LostFocus; 
    } 

    private void WatermarkedTextbox_LostFocus(object sender, EventArgs e) 
    { 
     if (Text.Length == 0) 
     { 
      ForeColor = SystemColors.InactiveCaption; 
      Text = _watermark; 
      IsWaterMarked = true; 
     } 
    } 

    private void WatermarkedTextbox_GotFocus(object sender, EventArgs e) 
    { 
     if (_isWatermarked) 
     { 
      ForeColor = SystemColors.ControlText; 
      Text = string.Empty; 
      IsWaterMarked = false; 
     } 
    } 

    protected void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
      handler(this, e); 
    } 

    protected void OnPropertyChanged(string propertyName) 
    { 
     OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

然後在主窗體上,您可以訂閱和處理程序添加到PropertyChanged事件:

//somewhere, like in the forms constructor, you need to subscribe to this event 
watermarkedTextbox2.PropertyChanged += watermarkedTextbox2_PropertyChanged; 

// the handler function 
void watermarkedTextbox2_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName == "IsWaterMarked") 
    { 
     if (watermarkedTextbox2.IsWaterMarked) 
      ; //handle here 
     else 
      ; //handle here 
    } 
} 
1

Windows支持水印文字盒子(和其他編輯控件,如組合框),他們稱之爲「提示橫幅」。但請注意,這不適用於多行文本框。

在受支持的控件上設置提示橫幅僅僅是使用Win32 API向包含水印文本的控件發送EM_SETCUEBANNER消息的問題。然後,Windows會處理檢測控件是空的還是有焦點,併爲您完成所有艱苦的工作,您將不需要使用事件來管理狀態。當您獲取控件的Text屬性時,提示橫幅也會被忽略。

我用下面的輔助類設置提示橫幅(作品組合框太):

public class CueBannerHelper 
{ 
    #region Win32 API's 
    [StructLayout(LayoutKind.Sequential)] 
    public struct COMBOBOXINFO 
    { 
     public int cbSize; 
     public RECT rcItem; 
     public RECT rcButton; 
     public IntPtr stateButton; 
     public IntPtr hwndCombo; 
     public IntPtr hwndItem; 
     public IntPtr hwndList; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct RECT 
    { 
     public int left; 
     public int top; 
     public int right; 
     public int bottom; 
    } 


    /// <summary>Used to get the current Cue Banner on an edit control.</summary> 
    public const int EM_GETCUEBANNER = 0x1502; 
    /// <summary>Used to set a Cue Banner on an edit control.</summary> 
    public const int EM_SETCUEBANNER = 0x1501; 


    [DllImport("user32.dll")] 
    public static extern bool GetComboBoxInfo(IntPtr hwnd, ref COMBOBOXINFO pcbi); 

    [DllImport("user32.dll")] 
    public static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); 
    #endregion 

    #region Method members 
    public static void SetCueBanner(Control control, string cueBanner) { 
     if (control is ComboBox) { 
      CueBannerHelper.COMBOBOXINFO info = new CueBannerHelper.COMBOBOXINFO(); 
      info.cbSize = Marshal.SizeOf(info); 

      CueBannerHelper.GetComboBoxInfo(control.Handle, ref info); 

      CueBannerHelper.SendMessage(info.hwndItem, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner); 
     } 
     else { 
      CueBannerHelper.SendMessage(control.Handle, CueBannerHelper.EM_SETCUEBANNER, 0, cueBanner); 
     } 
    } 
    #endregion 
} 

所有那麼需要實現上的自定義TextBox控件水印以下屬性(在頂部的屬性是控件的設計時屬性):

/// <summary> 
/// Gets or sets the watermark that the control contains. 
/// </summary> 
[Description("The watermark that the control contains."), 
    Category("Appearance"), 
    DefaultValue(null), 
    Browsable(true) 
] 
public string Watermark { 
    get { return this._watermark; } 
    set { 
     this._watermark = value; 
     CueBannerHelper.SetCueBanner(this, value); 
    } 
}