2016-05-09 8 views
2

Ich erstelle ein benutzerdefiniertes Steuerelement (ein Textfeld mit Wasserzeichen) und es erbt von Textbox. Ab sofort zeigt das Textfeld korrekt das Wasserzeichen an, wenn der Fokus verloren geht, wenn kein Text vorhanden ist, und löscht es, wenn das Textfeld den Fokus erhält (es ändert sogar die Textfarbe, wenn es das Wasserzeichen ist). Ich möchte, dass es meldet, dass es keinen Text hat, wenn es das Wasserzeichen zeigt, also versuche ich, die Texteigenschaft zu überschreiben.Überschriebene Text-Eigenschaft eines Textfelds wird nicht ordnungsgemäß aktualisiert

-Code wie folgt:

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

Problem ist, wenn das Textfeld den Fokus erhält es nicht das Wasserzeichen nicht löschen.

Was vermisse ich/mache ich hier falsch?

+0

können Sie einfach eine neue Eigenschaft machen und setzen Sie den Wert in dem Text überschreiben? – Jacobr365

+0

Mögliches Duplikat von [Wie implementiere ich eine TextBox, die "Type here" anzeigt?] (Http://stackoverflow.com/questions/2487104/how-do-i-implement-a-textbox-that-dypes- hier) – raidensan

+1

Ihr überschriebener Texteigenschaften-Getter wird auch von Winforms aufgerufen. Wird verwendet, um zu überprüfen, ob die TextBox neu gezeichnet werden muss. Wenn dies der Fall ist, hat das Feld isWatermarked noch nicht den richtigen Wert. Verschieben Sie einfach die isWatermarked-Zuweisung * vor * die Text-Zuweisung und es wird funktionieren. –

Antwort

0

Hans Passant Kommentar war die richtige Antwort auf meine Frage. Danke auch an alle, die sich Zeit genommen haben, Hilfe anzubieten.

Ich entschied mich schließlich, die einfachste Route zu gehen (Handhabung PropertyChanged scheint zu kompliziert für diesen besonderen Bedarf scheint und Haken Windows APIs lässt mehrzeilige Textfelder, so dass es keine Option ist).

Im Fall muss jemand es, hier ist der Code:

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

Löschen Sie Ihre überschriebene Text-Eigenschaft, dann wird es funktionieren!

diese Zeilen löschen:

[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

Der Zweck des Überschreibens der Eigenschaft Text besteht darin, zu melden, dass das Textfeld keinen Text enthält, wenn das Wasserzeichen angezeigt wird. Wenn Sie dies nicht tun, werden alle überprüft, ob die Textbox einen gültigen Text enthält, obwohl dies tatsächlich nicht der Fall ist. –

1

Ah sorry ich nicht so eindeutig gelesen. Alternativ möchten Sie möglicherweise nicht durch Überschreiben der Texteigenschaft benachrichtigen.

Sie können von Fall als solche machen:

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

Dann auf dem Hauptformular können Sie einen Handler zum Property Ereignis abonnieren und fügen:

//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 unterstützt Watermarking für Text Felder (und andere Bearbeitungssteuerelemente wie Kombinationsfelder) nennen sie das "Stichwort-Banner". Beachten Sie jedoch, dass dies bei mehrzeiligen Textfeldern nicht funktioniert.

Das Setzen des Cue-Banners auf einem unterstützten Steuerelement ist einfach eine Frage der Verwendung der Win32-API zum Senden einer EM_SETCUEBANNER-Nachricht an das Steuerelement, das den Wasserzeichentext enthält. Windows erkennt dann, wenn das Steuerelement leer ist oder den Fokus hat und die ganze Arbeit für Sie erledigt, Sie müssen keine Ereignisse zur Verwaltung des Status verwenden. Das Stichwort-Banner wird auch ignoriert, wenn Sie die Eigenschaft Text des Steuerelements abrufen.

Ich verwende die folgende Hilfsklasse die Cue-Banner (Werke für Kombinationsfelder zu) setzen:

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 
} 

Alles wird dann erforderlich, um das Wasserzeichen auf dem benutzerdefinierten TextBox-Steuerelement zu implementieren ist die folgende Eigenschaft (das an der Spitze Attribut ist für die Entwurfszeit-Eigenschaften der Kontrolle):

/// <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); 
    } 
} 
Verwandte Themen