Если пользователь введет 1985 в поле пароля, будут показаны четыре маркера (●●●●). Как я могу показать каждую введенную букву или цифру в течение нескольких секунд, а после этого изменить их на маркер? Я полагаю, что это невозможно сделать в поле пароля, но есть ли другой способ сделать это?
Как показать символы в течение нескольких секунд в поле пароля WPF?
Ответы (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 отображает символ «маркированный» пароль.
Этого можно добиться, используя всего один файл 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
Я реализовал аналогичную функциональность, оставив здесь в качестве более простого примера: поле пароля заменено текстовым полем, чтобы показывать пароль при наведении мыши на поле пароля следующим образом.
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 в коде позади