2009-10-22 54 views
4

WPF水印PasswordBox我使用水印的文本框为Watermark TextBox in WPF从水印文本框

<Grid Grid.Row="0" Background="{StaticResource brushWatermarkBackground}" Style="{StaticResource EntryFieldStyle}" > 
     <TextBlock Margin="5,2" Text="This prompt dissappears as you type..." Foreground="{StaticResource brushWatermarkForeground}" 
        Visibility="{Binding ElementName=txtUserEntry, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" /> 
     <TextBox Name="txtUserEntry" Background="Transparent" BorderBrush="{StaticResource brushWatermarkBorder}" /> 
    </Grid> 

我如何应用此一PasswordBox?

回答

15

一般的方法是一样的:你写的自定义控件的风格,并显示水印,只要密码箱是空的。这里唯一的问题是PasswordBox.Password属性不是一个依赖属性,你不能在触发器中使用它。此外密码箱被密封,所以你不能重写这个通知行为。但是你可以在这里使用附加属性。以下代码演示了如何。

XAML

<Window x:Class="WpfTest.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:WpfTest="clr-namespace:WpfTest" 
    Title="Password Box Sample" Height="300" Width="300"> 
    <Window.Resources> 
    <Style x:Key="{x:Type PasswordBox}" 
     TargetType="{x:Type PasswordBox}"> 
     <Setter Property="WpfTest:PasswordBoxMonitor.IsMonitoring" 
       Value="True"/> 
     <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type PasswordBox}"> 
      <Border Name="Bd" 
        Background="{TemplateBinding Background}" 
        BorderThickness="{TemplateBinding BorderThickness}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        SnapsToDevicePixels="true"> 
       <Grid> 
       <ScrollViewer x:Name="PART_ContentHost" 
           SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
       <TextBlock Text="Please enter your password" 
          Margin="4, 2, 0, 0" 
          Foreground="Gray" 
          Visibility="Collapsed" 
          Name="txtPrompt" /> 
       </Grid> 
      </Border> 
      <ControlTemplate.Triggers> 
       <Trigger Property="IsEnabled" 
             Value="false"> 
       <Setter TargetName="Bd" 
              Property="Background" 
              Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> 
       <Setter Property="Foreground" 
              Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> 
       </Trigger> 
       <Trigger Property="WpfTest:PasswordBoxMonitor.PasswordLength" Value="0"> 
       <Setter Property="Visibility" TargetName="txtPrompt" Value="Visible"/> 
       </Trigger> 
      </ControlTemplate.Triggers> 
      </ControlTemplate> 
     </Setter.Value> 
     </Setter> 
    </Style> 
    </Window.Resources> 
    <Grid> 
    <PasswordBox VerticalAlignment="Top"/> 
    </Grid> 
</Window> 

C#

using System.Windows; 
using System.Windows.Controls; 

namespace WpfTest 
{ 
    public partial class Window1 : Window 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
     } 

    } 

    public class PasswordBoxMonitor : DependencyObject 
    { 
    public static bool GetIsMonitoring(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsMonitoringProperty); 
    } 

    public static void SetIsMonitoring(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsMonitoringProperty, value); 
    } 

    public static readonly DependencyProperty IsMonitoringProperty = 
     DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(PasswordBoxMonitor), new UIPropertyMetadata(false, OnIsMonitoringChanged)); 



    public static int GetPasswordLength(DependencyObject obj) 
    { 
     return (int)obj.GetValue(PasswordLengthProperty); 
    } 

    public static void SetPasswordLength(DependencyObject obj, int value) 
    { 
     obj.SetValue(PasswordLengthProperty, value); 
    } 

    public static readonly DependencyProperty PasswordLengthProperty = 
     DependencyProperty.RegisterAttached("PasswordLength", typeof(int), typeof(PasswordBoxMonitor), new UIPropertyMetadata(0)); 

    private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var pb = d as PasswordBox; 
     if (pb == null) 
     { 
     return; 
     } 
     if ((bool) e.NewValue) 
     { 
     pb.PasswordChanged += PasswordChanged; 
     } 
     else 
     { 
     pb.PasswordChanged -= PasswordChanged; 
     } 
    } 

    static void PasswordChanged(object sender, RoutedEventArgs e) 
    { 
     var pb = sender as PasswordBox; 
     if (pb == null) 
     { 
     return; 
     } 
     SetPasswordLength(pb, pb.Password.Length); 
    } 
    } 
} 

请XAML代码通知PasswordBoxMonitor。

+1

嗨虽然这篇文章是相当老,但你能告诉我请如何在Windows Phone 8中实现这一点?我已经尝试了上述步骤,但似乎 是不是有在Windows手机8.我怎么能做到,如果我想建立了Windows Phone 8级的应用程序与文本框和密码有水印的盒子,请帮忙。 – Debhere 2013-06-12 12:54:05

3

你可以使用我的方法的水印行为。所有你所要做的就是复制并粘贴TextBoxWatermarkBehavior和变化Behavior<TextBox>Behavior<PasswordBox>

你可以找到一个演示项目here

+0

它工作得很好。我认为这应该是答案..谢谢 – 2013-07-03 11:39:30

+0

身份证猜测也是如此,但你有英文解释吗?谷歌翻译不是最精确的翻译 – ThrowingDwarf 2016-05-11 08:22:14

+0

@blindmeis,谢谢。你的建议对我有用。我已经修改了TextBoxWatermarkBehavior类如你所说,最终PasswordBoxWatermarkBehavior类,我已经给了它[作为一个单独的答案(http://stackoverflow.com/a/38518083/1977871) – VivekDev 2016-07-22 04:24:29

8

您可以显示/隐藏自己的背景,而不是使用触发器:

XAML:

<PasswordBox x:Name="passwordBox" PasswordChanged="passwordChanged" 
     Background="{StaticResource PasswordHint}" /> 

后面的代码:

// helper to hide watermark hint in password field 
private void passwordChanged(object sender, RoutedEventArgs e) 
{   
    if (passwordBox.Password.Length == 0) 
     passwordBox.Background.Opacity = 1; 
    else 
     passwordBox.Background.Opacity = 0; 
} 
+0

这是我能找到简单的解决方案,尽管我花了一些时间来理解这里的Background属性。如果在答案中有“PasswordHint”的声明会更好。然而,工作非常好... +1 – Bravo 2016-05-11 04:53:34

+0

我编辑了这个答案,以包含对StaticResource的一个名为PasswordHint的引用。为我工作,而且简单。 – jaybong 2016-09-06 09:46:51

+0

正如在评论中提到的,你缺少对* PasswordHint *的解释,从而使你的答案不完整 – 2017-09-14 14:51:44

0

@ blindmeis的suggestion is good。对于PasswordBox,该类将如下所示。

public class PasswordBoxWatermarkBehavior : System.Windows.Interactivity.Behavior<PasswordBox> 
{ 
    private TextBlockAdorner adorner; 
    private WeakPropertyChangeNotifier notifier; 

    #region DependencyProperty's 

    public static readonly DependencyProperty LabelProperty = 
     DependencyProperty.RegisterAttached("Label", typeof(string), typeof(PasswordBoxWatermarkBehavior)); 

    public string Label 
    { 
     get { return (string)GetValue(LabelProperty); } 
     set { SetValue(LabelProperty, value); } 
    } 

    public static readonly DependencyProperty LabelStyleProperty = 
     DependencyProperty.RegisterAttached("LabelStyle", typeof(Style), typeof(PasswordBoxWatermarkBehavior)); 

    public Style LabelStyle 
    { 
     get { return (Style)GetValue(LabelStyleProperty); } 
     set { SetValue(LabelStyleProperty, value); } 
    } 

    #endregion 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     this.AssociatedObject.Loaded += this.AssociatedObjectLoaded; 
     this.AssociatedObject.PasswordChanged += AssociatedObjectPasswordChanged; 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     this.AssociatedObject.Loaded -= this.AssociatedObjectLoaded; 
     this.AssociatedObject.PasswordChanged -= this.AssociatedObjectPasswordChanged; 

     this.notifier = null; 
    } 

    private void AssociatedObjectPasswordChanged(object sender, RoutedEventArgs e) 
    { 
     this.UpdateAdorner(); 
    } 

    private void AssociatedObjectLoaded(object sender, System.Windows.RoutedEventArgs e) 
    { 
     this.adorner = new TextBlockAdorner(this.AssociatedObject, this.Label, this.LabelStyle); 

     this.UpdateAdorner(); 

     //AddValueChanged for IsFocused in a weak manner 
     this.notifier = new WeakPropertyChangeNotifier(this.AssociatedObject, UIElement.IsFocusedProperty); 
     this.notifier.ValueChanged += new EventHandler(this.UpdateAdorner); 
    } 

    private void UpdateAdorner(object sender, EventArgs e) 
    { 
     this.UpdateAdorner(); 
    } 


    private void UpdateAdorner() 
    { 
     if (!String.IsNullOrEmpty(this.AssociatedObject.Password) || this.AssociatedObject.IsFocused) 
     { 
      // Hide the Watermark Label if the adorner layer is visible 
      this.AssociatedObject.TryRemoveAdorners<TextBlockAdorner>(); 
     } 
     else 
     { 
      // Show the Watermark Label if the adorner layer is visible 
      this.AssociatedObject.TryAddAdorner<TextBlockAdorner>(adorner); 
     } 
    } 
}