62

How can I do this in XAML:

PSEUDO-CODE:

<TextBox Text="{Binding Password}" Type="Password"/>

so that the user sees stars or dots when he is typing in the password.

I've tried various examples which suggest PasswordChar and PasswordBox but can't get these to work.

e.g. I can do this as shown here:

<PasswordBox Grid.Column="1" Grid.Row="1"
    PasswordChar="*"/>

but I of course want to bind the Text property to my ViewModel so I can send the value the bound TextBox when the button is clicked (not working with code behind), I want to do this:

<TextBox Grid.Column="1" Grid.Row="0" 
    Text="{Binding Login}" 
    Style="{StaticResource FormTextBox}"/>
<PasswordBox Grid.Column="1" Grid.Row="1"
    Text="{Binding Password}" 
    PasswordChar="*"
    Style="{StaticResource FormTextBox}"/>

But PasswordBox doesn't have a Text property.

Askolein
  • 3,250
  • 3
  • 28
  • 40
Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047

9 Answers9

39

To get or set the Password in a PasswordBox, use the Password property. Such as

string password = PasswordBox.Password;

This doesn't support Databinding as far as I know, so you'd have to set the value in the codebehind, and update it accordingly.

Brandon
  • 68,708
  • 30
  • 194
  • 223
  • Could mention: – user7116 Jul 13 '09 at 14:10
  • 5
    I don't think that actually works, at least not when I tried. – Brandon Jul 13 '09 at 14:11
  • if I define the value of my password box in code-behind, then it is no longer unit testable, surely I can bind the password from the viewmodel somehow – Edward Tanguay Jul 13 '09 at 14:11
  • As was mentioned in the question you found earlier (the accepted answer), there is a way to work around this issue, its just a matter of whether you think its worth the extra code. The code behind is the simplest way to do it. – Brandon Jul 13 '09 at 14:12
  • 1
    the article rightly states "it's a shame not to be able to use data binding" but it does offers a 2-page attached-property workaround, let's see if it actually works: http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html – Edward Tanguay Jul 13 '09 at 14:23
  • 3
    the reason for not allowing databinding on PasswordBox seems to be a security concern discussed here: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/7ca97b60-2d8e-4a27-8c5b-b8d5d7370a5e/ – Edward Tanguay Jul 13 '09 at 14:30
  • Ah, makes sense. Hopefully they manage to secure the databinding in the next release. Thanks for the link. – Brandon Jul 13 '09 at 14:33
  • 3
    I tested this solution and it works very nicely: http://blog.functionalfun.net/2008/06/wpf-passwordbox-and-data-binding.html – Edward Tanguay Jul 13 '09 at 14:48
19

As Tasnim Fabiha mentioned, it is possible to change font for TextBox in order to show only dots/asterisks. But I wasn't able to find his font...so I give you my working example:

<TextBox Text="{Binding Password}" 
     FontFamily="pack://application:,,,/Resources/#password" />

Just copy-paste won't work. Firstly you have to download mentioned font "password.ttf" link: https://github.com/davidagraf/passwd/blob/master/public/ttf/password.ttf Then copy that to your project Resources folder (Project->Properties->Resources->Add resource->Add existing file). Then set it's Build Action to: Resource.

After this you will see just dots, but you can still copy text from that, so it is needed to disable CTRL+C shortcut like this:

<TextBox Text="{Binding Password}" 
     FontFamily="pack://application:,,,/Resources/#password" > 
    <TextBox.InputBindings>
        <!--Disable CTRL+C (COPY) -->
        <KeyBinding Command="ApplicationCommands.NotACommand"
            Key="C"
            Modifiers="Control" />
        <!--Disable CTRL+X (CUT) -->
        <KeyBinding Command="ApplicationCommands.NotACommand"
            Key="X"
            Modifiers="Control" />
    </TextBox.InputBindings>
    <TextBox.ContextMenu>
        <!--Hide context menu where you could copy/cut as well -->
        <ContextMenu Visibility="Collapsed" />
    </TextBox.ContextMenu>
</TextBox>

EDIT: Added Ctrl+X and Context menu disabling based on @CodingNinja comment, thank you.

Kebechet
  • 1,461
  • 15
  • 31
  • This font did not work for me. The text stayed exactly the same and not with the password chars...If you have any tips I'd appreciate. Thanks – Luishg Sep 27 '19 at 20:02
  • 1
    For me it works(also tested on .NET 4.8). Try to play with FontFamily location, I think it could be slightly different and make sure you have it as RESOURCE. – Kebechet Oct 02 '19 at 11:48
  • Thanks! Worked perfectly for me. Was able to get dots showing and to disable CTRL-C. Really appreciate it! – Peter Steele Dec 01 '20 at 04:49
  • 1
    You are welcome. To make it 100% safe disable also CTRL+X (CUT) shortcut. – Kebechet Dec 01 '20 at 11:01
  • @Luishg I try the ssamko's solution and It doens't work for the first time. Then I write the complete path like this . Works fine now. – Dôn Kayt Aug 30 '21 at 10:21
  • 1
    @ssamko Don't forget copy/paste in the context menu! https://stackoverflow.com/a/3484929/4380178 – CodingNinja Oct 05 '21 at 12:33
  • Thank you very much. Its really so helpful. I am struggling to doing so .Also I need to add place holder. I can add placeholder and password character as well. – Rakibul Jan 11 '22 at 09:15
12

Send the passwordbox control as a parameter to your login command.

<Button Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=PasswordBox}"...>

Then you can call CType(parameter, PasswordBox).Password in your viewmodel.

Cody C
  • 3,087
  • 4
  • 24
  • 32
11

Thanks Cody, that was very helpful. I've just added an example for guys using the Delegate Command in C#

<PasswordBox x:Name="PasswordBox"
             Grid.Row="1" Grid.Column="1"
             HorizontalAlignment="Left" 
             Width="300" Height="25"
             Margin="6,7,0,7" />
<Button Content="Login"
        Grid.Row="4" Grid.Column="1"
        Style="{StaticResource StandardButton}"
        Command="{Binding LoginCommand}"
        CommandParameter="{Binding ElementName=PasswordBox}"
        Height="31" Width="92"
        Margin="5,9,0,0" />

 

public ICommand LoginCommand
{
   get
   {
        return new DelegateCommand<object>((args) =>
        {
            // Get Password as Binding not supported for control-type PasswordBox
            LoginPassword = ((PasswordBox) args).Password;

            // Rest of code here
        });
   }
}
Community
  • 1
  • 1
Kwex
  • 3,992
  • 1
  • 35
  • 28
  • This is what I have been looking for! My code-behind doesn't have the model. This worked well. Only change was that I had to use RelayCommand instead of DelegateCommand. – Waldron Jul 26 '23 at 21:01
9

There's a way to bind on a PasswordBox here: PasswordBox Databinding

gimpy
  • 1,129
  • 2
  • 13
  • 27
6

You can make your TextBox as customed PasswordBox by simply adding the following value to FontFamily property of your TextBox control.

<TextBox
    Text="{Binding Password}"
    FontFamily="ms-appx:///Assets/PassDot.ttf#PassDot"
    FontSize="35"/>

In my case this works perfectly. This will show dot in place of the actual text (not star(*) though).

Tasnim Fabiha
  • 1,148
  • 1
  • 17
  • 31
3

The problem with using the PasswordBox is that it is not very MVVM friendly due to the fact that it works with SecureString and therefore requires a shim to bind it to a String. You also cannot use the clipboard. While all these things are there for a reason, you may not require that level of security. Here is an alternative approach that works with the clipboard, nothing fancy. You make the TextBox text and background transparent and bind the text to a TextBlock underneath it. This textblock converts characters to * using the converter specified.

<Window.Resources>
    <local:TextToPasswordCharConverter x:Key="TextToPasswordCharConverter" />
</Window.Resources>

<Grid Width="200">
    <TextBlock Margin="5,0,0,0" Text="{Binding Text, Converter={StaticResource TextToPasswordCharConverter}, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" FontFamily="Consolas" VerticalAlignment="Center" />
    <TextBox Foreground="Transparent" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" FontFamily="Consolas" Background="Transparent" />
</Grid>

And here is the Value Converter:

class TextToPasswordCharConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new String('*', value?.ToString().Length ?? 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Make sure your Text property on your viewmodel implements INotifyPropertyChanged

David
  • 429
  • 3
  • 7
1

I did the below from the Views codebehind to set my property within the view model. Not sure if it really " breaks" the MVVM pattern but its the best and least complexe solution found.

  var data = this.DataContext as DBSelectionViewModel;

        data.PassKey = txtPassKey.Password;
Daniel_Uns
  • 21
  • 4
1

A simple resolution that worked for me was to bind the text box to the LocalPassword which displays a converted value of repeating *'s. Any entry is stored in the _localPassword variable.

<TextBox Text="{Binding LocalPassword}" />

private string _localPassword = null;
private string _localPasswordDisplayed { get => new string('*', _localPassword.Length); }
public string LocalPassword { get => _localPasswordDisplayed; set { _localPassword = value; OnPropertyChanged(); } }
Galactic
  • 400
  • 4
  • 14