2012-04-03 61 views
8

在浏览MSDN文档时,您可能会碰到这个gem:TextBox.Watermark。如何在Silverlight 4中使用TextBox.Watermark?

“太棒了!我一直想要一种内置的方式在我的文本框中添加水印!这非常棒,让我继续前进,并在XAML中设置!

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

不幸的是,如果你运行这个,你不会得到你所期望的:

enter image description here

和详细信息: enter image description here

这是什么?那么,请仔细阅读MSDN文档: enter image description here

没错。它在Silverlight 4中得到了支持,但它也说“不要在Silverlight 4应用程序中使用”。如果您确实使用它,则会收到System.NotImplemented异常。为了验证,这里是通过反射反编译属性的代码:

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

在那里,它是 - 它抛出一个异常,它不是在设计模式的任何时间。这没有意义吗?为什么微软会这样做?

不幸的是,我还没有找到任何明确的答案,但是如果我不得不猜测这是因为微软正计划在未来版本(也许是v5)的TextBox控件上实现水印行为并且希望有效地保留此属性因此第三方控件创建者不会对TextBox进行子类化并创建自己的Watermark属性。 我知道至少有一个控件供应商ComponentOne拥有一个从TextBox继承并提供Watermark属性的控件。 对我来说,这似乎是微软阻止人们在他们自己的TextBox子类中使用这个属性名称的方式。

回答

14

创建一个类库项目。添加类文件使用下面的代码.....之后,添加在此dll在您的项目。

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非常好的解决方案。顺便说一句,在Silverlight 5中工作正常。有趣的是,SL5 MSDN文档仍然具有与Watermark属性相同的冲突信息。 – 2012-09-05 17:13:40

+0

还要注意,我稍微调整了代码,主要是为了解决设计时错误(如果未设置水印属性)。更新的代码添加为下面的新答案。 – 2012-09-05 17:53:02

+0

你已经在构造函数中注册了事件,但是在卸载时你没有从它们注册(这很好),但是这带来了标签控制的问题,Tab控件将卸载它的内容并在适当的Tab被按下时加载,所以也许你应该注册到Loaded事件中的事件而不是构造函数。 – Sonosar 2013-07-17 08:15:01

2

那么你可以成功地在Silverlight使用5

试试这个链接: TextBox.Watermark

我成功地使用WatermarkTextBox在Silverlight 5 MVVM应用程序。

3

如果未设置水印属性,我修正了@mani kandan的解决方案以修复设计时错误。还添加了一个HasValue布尔属性,以便能够轻松检查用户是否在文本框中输入了文本,并最终更改为将所有空白条目视为非条目(即继续显示水印)。

修改后的代码:

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

创建一个类库项目。添加类文件中使用下面的代码

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

看看这个一个基于行为

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> 
相关问题