在浏览MSDN文档时,您可能会遇到此gem:TextBox.Watermark。
“太棒了!我一直想要一种内置的方法在我的文本框上做水印!这很棒,让我继续在XAML中设置它!”
<TextBox Watermark="This is my watermark" Margin="20"></TextBox>
不幸的是,如果你运行它,你将得不到你期望的结果:
细节:
这是什么?好吧,仔细查看MSDN文档:没错。 Silverlight 4支持它,但它也说“不要在Silverlight 4应用程序中使用”。如果您使用它,则会收到System.NotImplemented异常。要验证,这是通过Reflector反编译的属性的代码:
[EditorBrowsable(EditorBrowsableState.Never)]
public object Watermark
{
get
{
StubHelper.ThrowIfNotInDesignMode();
return base.GetValue(WatermarkProperty);
}
set
{
StubHelper.ThrowIfNotInDesignMode();
base.SetValue(WatermarkProperty, value);
}
}
它就是 - 它在任何时候都没有处于设计模式时抛出异常。这没有道理吗?为什么微软会这样做?
不幸的是我还没有找到任何确定的答案,但是如果我不得不猜测它是因为微软计划在未来的版本(也许是v5)中在TextBox控件上实现Watermark行为,并希望有效地保留这个属性第三方控件创建者不会将TextBox子类化并创建自己的Watermark属性。 我知道至少有一个控件供应商ComponentOne,它拥有一个继承自TextBox并提供Watermark属性的控件。 对我来说,似乎这是微软劝阻人们在自己的TextBox子类上使用这个属性名称的方式。
答案 0 :(得分: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>
答案 1 :(得分:3)
如果未设置Watermark属性,我会稍微修改@mani kandan的解决方案以修复设计时错误。还添加了一个HasValue布尔属性,以便能够轻松检查用户是否在TextBox中输入了文本,最后更改为将所有空白条目视为非条目(即,继续显示水印)。
修订代码:
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 :(得分:2)
答案 3 :(得分: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"/>
答案 4 :(得分: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>