I am including a sample program: it seems that when tabbing into the PasswordBox, entering text and tabbing out causes the PasswordBox to go blank. But double clicking in the PasswordBox, entering text and tabbing out does not. Why does this happen?
Edit: I discovered this also happens with a TextBox, so it isn't a bug specific to PasswordBox.
Steps to recreate each scenario:
Make the password disappear
- Click New.
- Single click in the first name field.
- Type something
- Press the TAB key
- Type something
- Press the TAB key
- Press the TAB key( yes twice else the Save event fires)
- Type something
- Notice the dots instead of text -PasswordBox is working!
- Press the TAB key.
- Amaze your friends as the PasswordBox goes blank!!
Make the password NOT disappear
- Click New.
- Single click in the first name field.
- Type something
- Press the TAB key
- Type something
- Double click in the password field.
- Type something
- Notice the dots instead of text -PasswordBox is working!
- Press the TAB key.
- Amaze your friends as the.. wait, the PasswordBox isn't blank? WTF?
Sample Code:
using System;
using System.Collections.ObjectModel;
namespace WpfApplication1 {
public sealed class MyData {
private ObservableCollection<MyDataRow> dataList;
public ObservableCollection<MyDataRow> DataList { get { return dataList; } }
public MyData() { dataList = new ObservableCollection<MyDataRow>(); }
public void AddBlankRow() { DataList.Add(new MyDataRow(this)); }
}
public sealed class MyDataRow {
private readonly MyData myData;
public MyDataRow(MyData myData) { this.myData = myData; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
}
}
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication1 {
public partial class MainWindow : Window {
private MyData Data { get { return (MyData)DataContext; } }
public MainWindow() { InitializeComponent(); }
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) {
PasswordBox pb = (PasswordBox)sender;
if (pb != null) {
MyDataRow row = pb.DataContext as MyDataRow;
if (row != null) { row.Password = pb.Password; }
}
}
private void Window_Loaded(object sender, RoutedEventArgs e) { DataContext = new MyData(); }
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { }
private void SaveExecute(object sender, ExecutedRoutedEventArgs e) { }
private void NewExecute(object sender, ExecutedRoutedEventArgs e) { Data.AddBlankRow(); }
private void CancelExecute(object sender, ExecutedRoutedEventArgs e) { Close(); }
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" WindowStartupLocation="CenterScreen" Closing="Window_Closing">
<Window.CommandBindings>
<CommandBinding Command="Save" Executed="SaveExecute" />
<CommandBinding Command="New" Executed="NewExecute" />
<CommandBinding Command="Close" Executed="CancelExecute" />
</Window.CommandBindings>
<Grid Margin="0,10,0,0">
<DataGrid ItemsSource="{Binding DataList}" ColumnWidth="*" Margin="10,0,9,38" HorizontalAlignment="Stretch"
AutoGenerateColumns="False" GridLinesVisibility="Horizontal"
HeadersVisibility="Column" HorizontalGridLinesBrush="LightGray" CanUserReorderColumns="False" Background="White" >
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<DataGridTemplateColumn Header="Password" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<PasswordBox PasswordChanged="PasswordBox_PasswordChanged" BorderThickness="0"
Height="23" HorizontalAlignment="Stretch"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button
Content="_New" Command="New"
Width="75" Height="23" Margin="10,10,10,10"
HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Button
Content="_Save" Command="Save"
IsDefault="True"
IsEnabled="True"
Width="75" Height="23" Margin="10,10,91,10"
HorizontalAlignment="Right" VerticalAlignment="Bottom" />
<Button
Content="Cancel" Command="Close"
IsEnabled="True"
Width="75" Height="23" Margin="10,10,10,10"
HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
</Window>
EDIT
Using data templates for both the CellTemplate and the EditingCellTemplate, My work around is simply to be consistent - always show something, (in this case an elipse). That way, no matter what, when the PasswordBox loses focus it changes back to the elipse. I think this is better than sometimes seeing bullet characters and sometimes seeing blank. David Edey's DataGrid_PreparingCellForEdit works perfectly for solving the double tab problem.
Here's my data templates.
<Grid.Resources>
<DataTemplate x:Key="PasswordTemplate" >
<Label BorderThickness="0" Height="23" HorizontalAlignment="Stretch" Content="..."/>
</DataTemplate>
<DataTemplate x:Key="EditingPasswordTemplate" >
<PasswordBox PasswordChanged="PasswordBox_PasswordChanged" BorderThickness="0"
Height="23" HorizontalAlignment="Stretch" />
</DataTemplate>
</Grid.Resources>