Как показать символы в течение нескольких секунд в поле пароля WPF?

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


person Simce    schedule 08.07.2011    source источник
comment
Как мобильный телефон, верно? Таким образом, пользователь может увидеть визуальное подтверждение того, что он набрал, если он не смотрит на клавиатуру: P   -  person Jerry Nixon    schedule 08.07.2011


Ответы (3)


Поместите текстовое поле поверх поля пароля, а затем используйте небольшую привязку данных и анимацию. Этот фрагмент 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 в анимации, чтобы получить желаемую задержку. Вы также можете изменить настройки шрифта в текстовом поле, чтобы набранный текст и символы пароля лучше совпадали.

ИЗМЕНИТЬ

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

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

<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 отображает символ «маркированный» пароль.

person Stewbob    schedule 08.07.2011
comment
Да, это один из способов. Я пытался сделать это в коде позади, но это решение лучше. Но есть одно маленькое дополнение. Клиент хочет видеть только последний введенный им символ. Это то, что я пытаюсь сделать. Я попытался сохранить то, что клиент ввел в строку, и просто заменить на пулю, но я не могу найти решение, которое будет работать так, как я объяснил :( Но большое спасибо !!!! :) - person Simce; 11.07.2011
comment
Спасибо за разъяснения. Это значительно меняет ответ. См. редактирование. - person Stewbob; 11.07.2011

Этого можно добиться, используя всего один файл 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"/>

Код С# позади:

    #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

person Devam Mehta    schedule 09.03.2013

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

xaml-код для окна

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

С# код позади

 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 в коде позади

person bugrasitemkar    schedule 25.04.2017