2012-04-03 14 views
8

Durante la navigazione nella documentazione MSDN, potresti incontrare questo gioiello: TextBox.Watermark.Come utilizzare TextBox.Watermark in Silverlight 4?

"Incredibile! Ho voluto un modo integrato per eseguire watermarking sulle mie caselle di testo! È fantastico, lasciami andare e impostalo in XAML!"

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

Purtroppo, se si esegue questo non sarà possibile ottenere quello che vi aspettate:

enter image description here

E dettaglio: enter image description here

Che cosa è questo? Bene, guarda la documentazione MSDN da vicino: enter image description here

Proprio così. È supportato in Silverlight 4, ma dice anche "Non utilizzare in un'applicazione Silverlight 4". Se lo si utilizza, si riceve un'eccezione System.NotImplemented. Per verificare, ecco il codice per la proprietà decompilato via Riflettore:

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

V'è - viene generata un'eccezione in qualsiasi momento non è nella modalità di progettazione. Questo non ha senso, giusto? Perché Microsoft dovrebbe fare questo?

Purtroppo non ho ancora trovato alcuna risposta definitiva, tuttavia se dovessi indovinare è perché Microsoft sta pianificando di implementare un comportamento Watermark sul controllo TextBox in una versione futura (forse v5) e volevo riservare efficacemente questa proprietà quindi i creatori di controlli di terze parti non sottoclassi TextBox e creano la loro proprietà Watermark. Conosco almeno un fornitore di controlli, ComponentOne, che ha un controllo che eredita da TextBox e fornisce una proprietà Watermark. Per me, sembra che questo sia il modo in cui Microsoft scoraggia le persone dall'usare questo nome di proprietà nelle loro sottoclassi TextBox.

risposta

14

Creare un progetto di libreria di una classe. Aggiungi file di classe usa il seguente codice ..... Dopo di ciò aggiungi The In this dll In Your Project.

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 per molto bella soluzione . A proposito, funziona bene con Silverlight 5. È interessante notare che la documentazione di SL5 MSDN ha ancora le stesse informazioni in conflitto sulla proprietà Watermark. –

+0

Nota anche che ho ottimizzato leggermente il codice, principalmente per risolvere l'errore in fase di progettazione se la proprietà Watermark non è impostata. Codice aggiornato aggiunto come nuova risposta di seguito. –

+0

Ti sei registrato agli eventi nel costruttore, ma nello scaricamento non sei registrato da loro (che va bene), ma questo porta a problemi con il controllo struttura a schede, il controllo Tab scaricherà il suo contenuto e verrà caricato quando viene premuta la scheda appropriata, quindi forse dovresti registrati agli eventi in evento Loaded invece di constructor. – Sonosar

2

si può usare con successo in Silverlight 5

Prova questo link: TextBox.Watermark

sto con successo utilizzando il WatermarkTextBox in Silverlight 5 Applicazione MVVM.

3

Ho rivisto leggermente la soluzione di @mani kandan per correggere l'errore in fase di progettazione se la proprietà Watermark non è impostata. Aggiunta anche una proprietà booleana HasValue per essere in grado di verificare facilmente se l'utente ha inserito il testo nel TextBox e infine modificato per trattare le voci di tutti gli spazi bianchi come non-voci (vale a dire, continuare a visualizzare la filigrana).

codice revisionato:

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

creare il progetto libreria di una classe.Aggiungi classe File utilizzare il seguente codice

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

Partenza questo sulla base di comportamenti

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> 
Problemi correlati