2012-04-03 7 views
8

Beim Durchsuchen der MSDN-Dokumentation stoßen Sie möglicherweise auf dieses Juwel: TextBox.Watermark.Wie verwende ich TextBox.Watermark in Silverlight 4?

"Super! Ich wollte eine integrierte Möglichkeit, Wasserzeichen auf meinen Textfeldern zu erstellen! Das ist großartig, lass mich weitermachen und setze das in XAML!"

<TextBox Watermark="This is my watermark" Margin="20"></TextBox> 

Leider, wenn Sie diese ausführen werden Sie nicht bekommen, was Sie erwarten:

enter image description here

Und das Detail: enter image description here

Was ist das? Nun, schauen Sie sich die MSDN-Dokumentation genau an: enter image description here

Das stimmt. Es wird in Silverlight 4 unterstützt, aber es sagt auch "Verwenden Sie nicht in einer Silverlight 4-Anwendung". Wenn Sie es verwenden, erhalten Sie eine System.NotImplemented-Ausnahme. Um zu überprüfen, hier ist der Code für die Eigenschaft über Reflector dekompilierten:

[EditorBrowsable(EditorBrowsableState.Never)] 
public object Watermark 
{ 
get 
{ 
StubHelper.ThrowIfNotInDesignMode(); 
return base.GetValue(WatermarkProperty); 
} 
set 
{ 
StubHelper.ThrowIfNotInDesignMode(); 
base.SetValue(WatermarkProperty, value); 
} 
} 

Es ist - es löst eine Ausnahme zu jeder Zeit es nicht im Entwurfsmodus ist. Das ergibt keinen Sinn oder? Warum würde Microsoft das tun?

Leider habe ich noch keine definitive Antwort gefunden, aber wenn ich raten musste, ist es, weil Microsoft plant, ein Watermark-Verhalten für das TextBox-Steuerelement in einer zukünftigen Version (vielleicht v5) zu implementieren und diese Eigenschaft effektiv reservieren wollte Daher erstellen Drittanbieter-Steuerelementersteller keine Unterklasse von TextBox und erstellen ihre eigene Watermark-Eigenschaft. Ich kenne mindestens einen Steuerelementanbieter, ComponentOne, der über ein Steuerelement verfügt, das von TextBox erbt und eine Watermark-Eigenschaft bereitstellt. Mir scheint, das ist Microsofts Weg, Menschen davon abzuhalten, diesen Eigenschaftsnamen für ihre eigenen TextBox-Unterklassen zu verwenden.

Antwort

14

Erstellen Sie ein Klassenbibliotheksprojekt. Add Class File benutzen Sie den folgenden Code ..... Danach fügen Sie die In dieser DLL In Ihrem Projekt.

public class WatermarkTextBox : TextBox 
{ 
    private bool displayWatermark = true; 
    private bool hasFocus = false; 
    public WatermarkTextBox() 
    { 
     this.GotFocus += new RoutedEventHandler(WatermarkTextBox_GotFocus); 
     this.LostFocus += new RoutedEventHandler(WatermarkTextBox_LostFocus); 
     this.TextChanged += new TextChangedEventHandler(WatermarkTextBox_TextChanged); 
     this.Unloaded += new RoutedEventHandler(WatermarkTextBox_Unloaded); 
    } 

    private void WatermarkTextBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     if (!hasFocus && Text == "") 
     { 
      setMode(true); 
      displayWatermark = true; 
      this.Text = Watermark; 
     } 
    } 

    private void WatermarkTextBox_Unloaded(object sender, RoutedEventArgs e) 
    { 
     this.GotFocus -= WatermarkTextBox_GotFocus; 
     this.LostFocus -= WatermarkTextBox_LostFocus; 
     this.Unloaded -= WatermarkTextBox_Unloaded; 
     this.TextChanged -= WatermarkTextBox_TextChanged; 
    } 

    private void WatermarkTextBox_GotFocus(object sender, RoutedEventArgs e) 
    { 
     hasFocus = true; 
     if (displayWatermark) 
     { 
      setMode(false); 
      this.Text = ""; 
     } 
    } 
    private void WatermarkTextBox_LostFocus(object sender, RoutedEventArgs e) 
    { 
     hasFocus = false; 
     if (this.Text == "") 
     { 
      displayWatermark = true; 
      setMode(true); 
      this.Text = Watermark; 
     } 
     else 
     { 
      displayWatermark = false; 
     } 
    } 
    private void setMode(bool watermarkStyle) 
    { 
     if (watermarkStyle) 
     { 
      this.FontStyle = FontStyles.Italic; 
      this.Foreground = new SolidColorBrush(Colors.Gray); 
     } 
     else 
     { 
      this.FontStyle = FontStyles.Normal; 
      this.Foreground = new SolidColorBrush(Colors.Black); 
     } 
    } 
    public new string Watermark 
    { 
     get { return GetValue(WatermarkProperty) as string; } 
     set { SetValue(WatermarkProperty, value); } 
    } 
    public static new readonly DependencyProperty WatermarkProperty = 
     DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkTextBox), new PropertyMetadata(watermarkPropertyChanged)); 
    private static void watermarkPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     WatermarkTextBox textBox = obj as WatermarkTextBox; 
     if (textBox.displayWatermark) 
     { 
      textBox.Text = e.NewValue.ToString(); 
      textBox.setMode(true); 
     } 
    } 

XAML:

xmlns:watertext="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1" 


    <watertext:WatermarkTextBox Watermark="WElcome" Margin="150,115,120,166"></watertext:WatermarkTextBox> 
+0

+1 für sehr schöne Lösung . Funktioniert übrigens in Silverlight 5 gut. Interessant zu beachten, dass SL5 MSDN-Dokumentation immer noch die gleichen widersprüchlichen Informationen über die Watermark-Eigenschaft enthält. –

+0

Beachten Sie auch, dass ich den Code etwas optimiert habe, hauptsächlich um Design-Time-Fehler zu beheben, wenn die Watermark-Eigenschaft nicht gesetzt ist. Aktualisierter Code, der unten als neue Antwort hinzugefügt wurde. –

+0

Sie haben sich bei Ereignissen im Konstruktor registriert, aber beim Entladen sind Sie nicht registriert (was in Ordnung ist), aber dies führt zu Problemen mit der Tab-Steuerung, Tab Control wird den Inhalt entladen und geladen, wenn die entsprechende Registerkarte gedrückt wird Register zu Ereignissen in Loaded-Ereignis statt Konstruktor. – Sonosar

2

Nun können Sie es erfolgreich in Silverlight verwenden 5

diesen Link ausprobieren: TextBox.Watermark

ich erfolgreich bin mit dem WatermarkTextBox in einem Silverlight 5 MVVM-Anwendung.

3

Ich überarbeitete @mani Kandans Lösung leicht, um den Entwurfszeitfehler zu beheben, wenn die Wasserzeicheneigenschaft nicht festgelegt wurde. Außerdem wurde eine HasValue-Boolean-Eigenschaft hinzugefügt, um leicht überprüfen zu können, ob der Benutzer Text in die TextBox eingegeben hat, und zuletzt geändert wurde, um Einträge mit allen Whitespaces als Nicht-Einträge zu behandeln (d. H. Weiterhin Wasserzeichen anzuzeigen).

Überarbeitete Code:

public class WatermarkTextBox : TextBox 
{ 

    private bool displayWatermark = true; 
    private bool hasFocus = false; 

    public WatermarkTextBox() 
    { 
     this.GotFocus += new RoutedEventHandler(WatermarkTextBox_GotFocus); 
     this.LostFocus += new RoutedEventHandler(WatermarkTextBox_LostFocus); 
     this.TextChanged += new TextChangedEventHandler(WatermarkTextBox_TextChanged); 
     this.Unloaded += new RoutedEventHandler(WatermarkTextBox_Unloaded); 
    } 

    private void WatermarkTextBox_TextChanged(object sender, TextChangedEventArgs e) 
    { 
     if (!hasFocus && string.IsNullOrWhiteSpace(this.Text)) 
     { 
      setMode(true); 
      displayWatermark = true; 
      // avoid design-time error if Watermark not specified 
      this.Text = (Watermark == null ? string.Empty : Watermark); 
     } 
    } 

    private void WatermarkTextBox_Unloaded(object sender, RoutedEventArgs e) 
    { 
     this.GotFocus -= WatermarkTextBox_GotFocus; 
     this.LostFocus -= WatermarkTextBox_LostFocus; 
     this.Unloaded -= WatermarkTextBox_Unloaded; 
     this.TextChanged -= WatermarkTextBox_TextChanged; 
    } 

    private void WatermarkTextBox_GotFocus(object sender, RoutedEventArgs e) 
    { 
     hasFocus = true; 
     if (displayWatermark) 
     { 
      setMode(false); 
      this.Text = ""; 
     } 
    } 

    private void WatermarkTextBox_LostFocus(object sender, RoutedEventArgs e) 
    { 
     hasFocus = false; 
     if (string.IsNullOrWhiteSpace(this.Text)) 
     { 
      displayWatermark = true; 
      setMode(true); 
      this.Text = (Watermark == null ? string.Empty : Watermark); 
     } 
     else 
     { 
      displayWatermark = false; 
     } 
    } 

    private void setMode(bool watermarkStyle) 
    { 
     if (watermarkStyle) 
     { 
      this.FontStyle = FontStyles.Italic; 
      this.Foreground = new SolidColorBrush(Colors.Gray); 
     } 
     else 
     { 
      this.FontStyle = FontStyles.Normal; 
      this.Foreground = new SolidColorBrush(Colors.Black); 
     } 
    } 

    public new string Watermark 
    { 
     get { return GetValue(WatermarkProperty) as string; } 
     set { SetValue(WatermarkProperty, value); } 
    } 

    public static new readonly DependencyProperty WatermarkProperty = 
     DependencyProperty.Register("Watermark", typeof(string), typeof(WatermarkTextBox), new PropertyMetadata(watermarkPropertyChanged)); 
    private static void watermarkPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     WatermarkTextBox textBox = obj as WatermarkTextBox; 
     if (textBox.displayWatermark) 
     { 
      textBox.Text = e.NewValue.ToString(); 
      textBox.setMode(true); 
     } 
    } 

    public bool HasValue 
    { 
     get 
     { 
      // if watermark has been specified, then compare to text value to determine if text set by user, 
      // otherwise check to see if empty or whitespace. 
      if (this.Watermark != null) 
       return this.Watermark != this.Text; 
      else 
       return !string.IsNullOrWhiteSpace(this.Text); 
     } 
    } 

} 
2

Erstellen einer Klasse Bibliothek-Projekt.In der Klasse Datei den folgenden Code

using System; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Ink; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace Project.Controls 
{ 
    public class WatermarkEditBox : TextBox 
    { 

     TextBlock lbl = new TextBlock() 
     { 
      IsHitTestVisible = false, 
      Foreground = new SolidColorBrush(Colors.LightGray), 
      VerticalAlignment = VerticalAlignment.Center, 
      HorizontalAlignment = HorizontalAlignment.Left, 
      Margin = new Thickness(3,0,0,0) 
     }; 
     public string WatermarkText { get { return lbl.Text; } set { lbl.Text = value; } } 

     public WatermarkEditBox() 
     { 
      this.Loaded += WatermarkEditBox_Loaded; 
     } 

     void WatermarkEditBox_Loaded(object sender, RoutedEventArgs e) 
     { 
      this.UpdateLayout(); 
      Grid g = GetObjectOfType<Grid>(this, "RootElement"); 
      if (g != null) 
      { 
       g.Children.Add(lbl); 
      } 
      this.TextChanged += WatermarkEditBox_TextChanged; 
     } 

     void WatermarkEditBox_TextChanged(object sender, TextChangedEventArgs e) 
     { 
      if (this.Text.Length == 0) 
       lbl.Visibility = System.Windows.Visibility.Visible; 
      else 
       lbl.Visibility = System.Windows.Visibility.Collapsed; 
     } 

     public TObject GetObjectOfType<TObject>(DependencyObject parent, string name) where TObject : DependencyObject 
     { 
      int count = VisualTreeHelper.GetChildrenCount(parent); 
      for (int i = 0; i < count; ++i) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
       if (child is TObject && child.GetValue(NameProperty).ToString() == name) 
       { 
        return child as TObject; 
       } 
       else 
       { 
        TObject obj = GetObjectOfType<TObject>(child, name); 
        if (obj != null) 
        { 
         return obj; 
        } 
       } 
      } 

      return null; 
     } 

    } 
} 

XAML:

xmlns:Controls="clr-namespace:Project.Controls" 

<Controls:WatermarkEditBox WatermarkText="фильтр" Width="100"/> 
2

Schauen Sie sich dieses basierend auf Verhaltensweisen

namespace MyNamespace 
{ 
    public class WatermarkBehavior : Behavior<TextBox> 
    { 
     public String Watermark 
     { 
      get { return this.GetValue(WatermarkProperty) as String; } 
      set { this.SetValue(WatermarkProperty, value); } 
     } 

     public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(String), typeof(WatermarkBehavior), new PropertyMetadata("", new PropertyChangedCallback(OnWatermarkChanged))); 

     private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var behavior = d as WatermarkBehavior; 
      if (!String.IsNullOrWhiteSpace(e.NewValue as String)) 
      { 
       behavior.SetWatermarkIfNeeded(); 
      } 
     } 

     protected override void OnAttached() 
     { 
      base.OnAttached(); 
      this.AssociatedObject.GotFocus += GotFocus; 
      this.AssociatedObject.LostFocus += LostFocus; 
     } 

     protected override void OnDetaching() 
     { 
      base.OnDetaching(); 
      this.AssociatedObject.GotFocus -= GotFocus; 
      this.AssociatedObject.LostFocus -= LostFocus; 
     } 

     private void GotFocus(object sender, RoutedEventArgs e) 
     { 
      if (this.AssociatedObject.Text == this.Watermark) 
      { 
       this.AssociatedObject.Text = String.Empty; 
       this.AssociatedObject.Foreground = new SolidColorBrush(Colors.Black); 
      } 
     } 

     private void LostFocus(object sender, RoutedEventArgs e) 
     { 
      this.SetWatermarkIfNeeded(); 
     } 

     private void SetWatermarkIfNeeded() 
     { 
      if (String.IsNullOrWhiteSpace(this.AssociatedObject.Text)) 
      { 
       this.SetWatermark(); 
      } 
     } 

     private void SetWatermark() 
     { 
      this.AssociatedObject.Text = this.Watermark; 
      this.AssociatedObject.Foreground = new SolidColorBrush(Colors.Gray); 
     } 
    } 
} 

XAML

<UserControl x:Class="GreenField.Targeting.Controls.BasketTargets.EditorView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:MyNamespace" 
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
    mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> 
    <TextBox Text="{Binding Text}"> 
    <i:Interaction.Behaviors> 
     <local:WatermarkBehavior Watermark="{Binding Watermark}" /> 
    </i:Interaction.Behaviors> 
    </TextBox> 
</UserControl> 
Verwandte Themen