Pregunta

Estoy usando un cuadro de texto de marca de agua como en Cuadro de texto de marca de agua en 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>

¿Cómo puedo aplicar esto para un PasswordBox?

¿Fue útil?

Solución

El enfoque general es el mismo: escribe un estilo de control personalizado y muestra una marca de agua cada vez que el cuadro de contraseña está vacío. El único problema aquí es que la propiedad PasswordBox.Password no es una propiedad de dependencia, y no puede usarla en el disparador. También PasswordBox está sellado, por lo que no puede anular este comportamiento de notificación. Pero puede usar propiedades adjuntas aquí. El siguiente código demuestra cómo.

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);
    }
  }
}

Tenga en cuenta PasswordBoxMonitor en el código XAML.

Otros consejos

puede mostrar / ocultar el fondo usted mismo en lugar de usar disparadores:

XAML:

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

Código detrás:

// 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;
}

Puedes usar mi enfoque para un comportamiento de marca de agua.todo lo que tienes que hacer es copiar y pegar el TextBoxWatermarkBehavior y el cambio el Behavior<TextBox> a Behavior<PasswordBox>.

puedes encontrar un proyecto de demostración aquí

La sugerencia de @ blindmeis es buena . Para PasswordBox, la clase sería la siguiente.

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);
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top