【问题标题】:How to use TextBox.Watermark in Silverlight 4?如何在 Silverlight 4 中使用 TextBox.Watermark?
【发布时间】:2012-04-03 12:11:26
【问题描述】:

在浏览 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 控件上实现水印行为,并希望有效地保留此属性,所以第三方控件创建者不会继承 TextBox 并创建自己的 Watermark 属性。 我知道至少有一个控件供应商 ComponentOne,它有一个从 TextBox 继承并提供 Watermark 属性的控件。 在我看来,这似乎是 Microsoft 阻止人们在自己的 TextBox 子类中使用此属性名称的方式。

【问题讨论】:

    标签: .net silverlight-4.0


    【解决方案1】:

    创建一个类库项目。添加类文件使用以下代码.....之后在您的项目中添加这个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 非常好的解决方案。顺便说一句,在 Silverlight 5 中运行良好。有趣的是,SL5 MSDN 文档仍然有关于 Watermark 属性的相同冲突信息。
    • 还请注意,我稍微调整了代码,主要是为了解决未设置 Watermark 属性时的设计时错误。更新的代码添加为下面的新答案。
    • 您已在构造函数中注册了事件,但在卸载时您已从它们中注销(这很好),但这会给选项卡控件带来问题,选项卡控件将卸载其内容并在适当的选项卡时加载被按下,所以也许你应该在 Loaded 事件而不是构造函数中注册事件。
    【解决方案2】:

    如果未设置 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);
            }
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      根据行为检查这个

      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>
      

      【讨论】:

        【解决方案4】:

        你可以在 Silverlight 5 中成功使用它

        试试这个链接: TextBox.Watermark

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

        【讨论】:

          【解决方案5】:

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

          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"/>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-21
            • 1970-01-01
            • 2010-12-31
            相关资源
            最近更新 更多