2009-10-22 55 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); 
     } 
    } 
}