Как показать символы в течение нескольких секунд в поле пароля WPF? - PullRequest
13 голосов
/ 08 июля 2011

Если пользователь введет 1985 в поле пароля, будут показаны четыре маркера (●●●●). Как я могу показать каждую введенную букву или цифру в течение нескольких секунд, а после этого заменить ее на маркер? Я полагаю, что это не может быть сделано в поле пароля, но есть ли другой способ сделать это?

Ответы [ 3 ]

19 голосов
/ 08 июля 2011

Поместите текстовое поле поверх поля пароля, а затем используйте небольшую привязку данных и анимацию. Этот фрагмент XAML позволит текстовому полю быть видимым до тех пор, пока продолжается набор текста, но как только набор текста прекратится, текстовое поле исчезнет, ​​оставив только поле пароля с отображением символов пароля.

    <Window.Resources>
        <Storyboard x:Key="Storyboard1">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="textBox">
                <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="1"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="TextBoxBase.TextChanged" SourceName="textBox">
            <StopStoryboard BeginStoryboardName="Storyboard1_BeginStoryboard"/>
            <BeginStoryboard x:Name="Storyboard1_BeginStoryboard" Storyboard="{StaticResource Storyboard1}"/>
        </EventTrigger>
    </Window.Triggers>




<PasswordBox x:Name="passwordBox"/>
<TextBox x:Name="textBox"
        Text="{Binding ElementName=passwordBox, Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         Opacity="100"/>

Вы можете поиграться с KeyTimes в анимации, чтобы получить задержку, которую вы предпочитаете. Вы также можете изменить настройки шрифта в текстовом поле, чтобы печатный текст и символы пароля выстраивались в ряд лучше.

EDIT

Если вы хотите отобразить только последний символ, набранный в виде обычного текста:

Эта ситуация немного отличается и требует большей сложности. В этом сценарии используется только текстовое поле в окне, а не поле пароля.

<TextBox Name="tbxPwd" Margin="20,0" 
         Text="{Binding Path=DisplayedPwd}" />

В вашем коде для окна (или в вашем классе ViewModel) вам понадобятся два свойства, ActualPwd и DisplayedPwd. Текстовое поле привязано к свойству DisplayedPwd.

В коде позади вам понадобится следующий код:

Private Sub tbxPwd_PreviewKeyDown(sender As Object, e As System.Windows.Input.KeyEventArgs) _
  Handles tbxPwd.PreviewKeyDown

  If e.Key = Key.Back Then
     If ActualPwd.Length > 0 Then
        //Remove the last character.
        ActualPwd = ActualPwd.Substring(0, ActualPwd.Length - 1)
        ShowLastCharacter()
        tbxPwd.CaretIndex = DisplayedPwd.Length
     End If
  End If

End Sub

Private Sub tbxPwd_PreviewTextInput(sender As Object, e As System.Windows.Input.TextCompositionEventArgs) _
  Handles tbxPwd.PreviewTextInput

  ActualPwd &= e.Text
  e.Handled = True

  ShowLastCharacter()

  tbxPwd.CaretIndex = DisplayedPwd.Length

End Sub

Private Sub ShowLastCharacter()
  Dim lastChar As Char = ActualPwd.Substring(ActualPwd.Length - 1)

  //Reset the displayed pwd.
  DisplayedPwd = ""
  For i As Int32 = 0 To ActualPwd.Length - 2
     DisplayedPwd &= "•"
  Next
  DisplayedPwd &= lastChar

End Sub

Метод tbxPwd_PreviewTextInput используется для извлечения символа, набранного пользователем. Метод tbxPwd_PreviewKeyDown используется для извлечения ключа BackSpace или любой другой клавиши управляющего символа, которую вы хотите обнаружить.

В этом коде нет задержки, поэтому он всегда отображает последний символ строки пароля в виде открытого текста. Должно быть достаточно легко добавить некоторый код вместе с таймером, чтобы после некоторой задержки изменить последний символ на символ pwd.

Приведенный выше код не был тщательно отлажен, поэтому могут возникнуть проблемы, если пользователь удаляет весь свой пароль, чтобы начать все сначала.

Совет: Alt + 0149 отображает символ пароля «bullet».

2 голосов
/ 09 марта 2013

Этого можно достичь, используя только один TextBox. Смотрите код ниже:

XAML-код для окна:

    <Label x:Name="Pwd" Height="30" Width="70" HorizontalAlignment="Left" FontSize="14"
           Margin="10,10,0,0" VerticalAlignment="Top" Content="Password:"/>
    <TextBox x:Name="textBox" Width="130" Height="30" Margin="30,10,0,0" 
             VerticalAlignment="Top" MaxLength="12" FontSize="14"
             PreviewKeyDown="TextBox_PreviewKeyDown" 
             KeyDown="TextBox_KeyDown" />
    <CheckBox x:Name="ckhShowPassword" Height="30" 
              Content="Show password characters" 
              Margin="69,0,59,42" VerticalAlignment="Bottom" 
              Checked="ckhShowPassword_Checked" Unchecked="ckhShowPassword_UnChecked"/>
    <Label x:Name="lblActualPwd" Height="30" Width="200" 
           Margin="10,100,0,0" VerticalAlignment="Top" FontSize="14"
           HorizontalAlignment="Center" HorizontalContentAlignment="Center"/>

C # Код:

    #region "CLASS LEVEL VARIABLES"
    System.Windows.Threading.DispatcherTimer dispatcherTimer = 
        new System.Windows.Threading.DispatcherTimer();
    string actualPwd = "";
    #endregion

    #region "WINDOW EVENTS"
    public Window2()
    {
        InitializeComponent();
    }

    private void Window2_Loaded(object sender, RoutedEventArgs e)
    {
        lblActualPwd.Visibility = Visibility.Hidden;
        textBox.Focus();
    }
    #endregion

    #region "TEXTBOX EVENTS"
    private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key != Key.Back)
        {
            actualPwd += GetCharFromKey(e.Key); //Store actual characters for later retrieval        
        }
        else if (e.Key == Key.Back)
        {
            if (actualPwd.Length > 0)
                actualPwd = actualPwd.Remove(actualPwd.Length - 1);
            else
                actualPwd = "";
        }
        else
        {
            actualPwd += GetCharFromKey(e.Key);
        }

        string str = "";
        for (int i = 0; i < textBox.Text.Length; i++)
            str += char.ConvertFromUtf32(8226);

        textBox.Text = str;
        textBox.Select(textBox.Text.Length, 0);
    }

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1);
        dispatcherTimer.Start();
    }
    #endregion

    #region "DISPATCHER EVENT"
    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {   
        string str = "";
        for(int i = 0; i < textBox.Text.Length; i++)
            str += char.ConvertFromUtf32(8226);

        textBox.Text = str;
        textBox.Select(textBox.Text.Length, 0);
    }
    #endregion

    #region "CHECKBOX EVENTS"
    private void ckhShowPassword_Checked(object sender, RoutedEventArgs e)
    {
        if (actualPwd.Length > 0)
        {
            lblActualPwd.Foreground = Brushes.Blue;
            lblActualPwd.Content = actualPwd;
            lblActualPwd.Visibility = Visibility.Visible;
        }
        else
        {
            lblActualPwd.Foreground = Brushes.Red;
            lblActualPwd.Content = "Please input password.";
            lblActualPwd.Visibility = Visibility.Visible;
        }
    }

    private void ckhShowPassword_UnChecked(object sender, RoutedEventArgs e)
    {
        lblActualPwd.Content = string.Empty;
        lblActualPwd.Visibility = Visibility.Hidden;
    }
    #endregion

    #region "ENUM TYPE - MAP KEY TO CHARACTER"
    public enum MapType : uint
    {
        MAPVK_VK_TO_VSC = 0x0,
        MAPVK_VSC_TO_VK = 0x1,
        MAPVK_VK_TO_CHAR = 0x2,
        MAPVK_VSC_TO_VK_EX = 0x3,
    }
    #endregion

    #region "INTEROP DLL IMPORT"
    [DllImport("user32.dll")]
    public static extern bool GetKeyboardState(byte[] lpKeyState);
    [DllImport("user32.dll")]
    public static extern uint MapVirtualKey(uint uCode, MapType uMapType);
    [DllImport("user32.dll")]
    #endregion

    #region "VIRTUAL KEY UNICODE CONVERSION"
    public static extern int ToUnicode(
     uint wVirtKey,
     uint wScanCode,
     byte[] lpKeyState,
     [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)] 
    StringBuilder pwszBuff,
     int cchBuff,
     uint wFlags);
    #endregion

    #region "FUNCTION - CHAR FROM KEY"
    public static char GetCharFromKey(Key key)
    {
        char ch = ' ';

        int virtualKey = KeyInterop.VirtualKeyFromKey(key);
        byte[] keyboardState = new byte[256];
        GetKeyboardState(keyboardState);

        uint scanCode = MapVirtualKey((uint)virtualKey, MapType.MAPVK_VK_TO_VSC);
        StringBuilder stringBuilder = new StringBuilder(2);

        int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
        switch (result)
        {
            case -1:
                break;
            case 0:
                break;
            case 1:
                {
                    ch = stringBuilder[0];
                    break;
                }
            default:
                {
                    ch = stringBuilder[0];
                    break;
                }
        }
        return ch;
    }
    #endregion

MapType enum извлечено из MapType

0 голосов
/ 25 апреля 2017

Я реализовал аналогичную функциональность, оставив здесь в качестве более простого примера, поле пароля заменено на текстовое поле, чтобы показывать пароль при наведении курсора мыши на поле пароля следующим образом

xaml код для окна

 <PasswordBox Name="LicencePasswordBox" MouseEnter="LicencePasswordBox_MouseEnter"></PasswordBox>
 <TextBox IsReadOnly="True" Name="LicencePasswordTextBox" MouseLeave="LicencePasswordBox_MouseLeave" Visibility="Hidden"></TextBox>

c # код позади

 private void LicencePasswordBox_MouseEnter(object sender, MouseEventArgs e)
    {
        LicencePasswordBox.Visibility = Visibility.Hidden;
        LicencePasswordTextBox.Visibility = Visibility.Visible;
    }

    private void LicencePasswordBox_MouseLeave(object sender, MouseEventArgs e)
    {
        LicencePasswordBox.Visibility = Visibility.Visible;
        LicencePasswordTextBox.Visibility = Visibility.Hidden;
    }

Кроме того, если вы разрабатываете mvp или mvp-vm wpf-приложение, не забудьте связать значение как с LicencePasswordBox, так и с LicencePasswordTextBox в коде

...