0

Explanation:

I have one checkbox named hide password and two textboxes named password and conform password respectively.Those two textboxes have been already binded with the old password as follows.

Password: Apple
Conform Password: Apple

Once I select the hide password checkbox,the old password which is already in the password textbox and conform password textbox, should change to ******** .

For Example: If my old password is Apple as soon as I check the hide password checkbox it should change to ***** as follows.

Password: *****
Conform password: *****

Is it possible with c# (wpf) using MVVM?

GJPD
  • 89
  • 1
  • 9
  • https://www.w3schools.com/howto/howto_js_toggle_password.asp – David784 Jan 19 '19 at 03:37
  • But I need c# code...@David784 – GJPD Jan 19 '19 at 03:40
  • @GJPD that's not [how this site works](https://stackoverflow.com/help/how-to-ask). – Mark Feldman Jan 19 '19 at 03:58
  • I have edited my question up to my knowledge ....Someone help me.. – GJPD Jan 19 '19 at 04:15
  • 1
    Why not use `PasswordBox` that's what it's for. You can set and clear the mask and it stores the password in a secure string. [This may help](https://stackoverflow.com/questions/8185747/how-can-i-unmask-password-text-box-and-mask-it-back-to-password) – JSteward Jan 19 '19 at 04:18
  • But, Is it possible to bind two properties to one password box?......I actually need it for this purpose https://stackoverflow.com/questions/54264195/is-it-posssible-to-bind-two-properties-to-single-textbox-using-mvvm-c @JSteward – GJPD Jan 19 '19 at 05:04

2 Answers2

1

The following solution uses a TextBox to show the password in plain text and a PasswordBox to mask the password. The PasswordBox is on top of the TextBox, so at first you'd see the password masked. When the "show password" checkbox is checked, the PasswordBox is hidden, thereby showing the TextBox beneath (and the password in plain text). Here's the XAML:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</Window.Resources>

<StackPanel>
    <Grid>
        <TextBox
            Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"
            />
        <PasswordBox
            x:Name="PasswordBox"
            PasswordChanged="OnPasswordChanged"
            Visibility="{Binding HidePassword, Converter={StaticResource VisibilityConverter}}"
            />
    </Grid>
    <CheckBox
        Content="Show password"
        IsChecked="{Binding ShowPassword}"
        />
</StackPanel>

It doesn't use MVVM for everything (notice the OnPasswordChanged event handler). This is because the PasswordBox can't use binding, so the password must be set in the code-behind. But before showing that, here's the view model:

public class ViewModel : ViewModelBase
{
    private string _password;
    public string Password
    {
        get => _password;
        set => Set(ref _password, value);
    }

    private bool _showPassword;
    public bool ShowPassword
    {
        get => _showPassword;
        set
        {
            Set(ref _showPassword, value);
            RaisePropertyChanged(nameof(HidePassword));
        }
    }

    public bool HidePassword => !ShowPassword;
}

The Set methods come from the ViewModelBase parent class, which is part of the MVVM Light Toolkit. The Set method simply sets the property's backing field and raises the PropertyChanged event for that property.

Finally, here's the code behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        InitializeViewModel();
    }

    public ViewModel ViewModel => DataContext as ViewModel;

    private void InitializeViewModel()
    {
        DataContext = new ViewModel();

        ViewModel.PropertyChanged += (sender, args) =>
        {
            // Update the password box only when it's not visible;
            // otherwise, the cursor goes to the beginning on each keystroke
            if (!PasswordBox.IsVisible)
            {
                if (args.PropertyName == nameof(ViewModel.Password))
                    PasswordBox.Password = ViewModel.Password;
            }
        };
    }

    private void OnPasswordChanged(object sender, RoutedEventArgs e)
    {
        ViewModel.Password = PasswordBox.Password;
    }
}

After setting the DataContext to a new ViewModel, we listen to changes to the Password property so that we update it in the PasswordBox. Notice that we only do this when the PasswordBox is not visible (otherwise, the cursor is set to the beginning on each keystroke and we end up with the password reversed!)

The event handler simply updates the Password in the view model whenever it's changed in the PasswordBox.

The code for the "confirm password" TextBox and PasswordBox would be very similar.

redcurry
  • 2,381
  • 2
  • 24
  • 38
  • you are requested to see the following post as well to understand my requirements completely https://stackoverflow.com/questions/54264195/is-it-posssible-to-bind-two-properties-to-single-textbox-using-mvvm-c @redcurry – GJPD Jan 19 '19 at 05:43
  • @GJPD Questions should be as self contained as possible. If your question needs to be expanded to fully explain your problem, please edit your question. – redcurry Jan 19 '19 at 05:47
  • okay...is it possible to do what you said without adding anything in code behind? @redcurry – GJPD Jan 19 '19 at 05:54
  • @GJPD Not if you're going to use the `PasswordBox`. It doesn't support data-binding for security reasons, so we're forced to use code behind. – redcurry Jan 19 '19 at 05:57
  • k...Thank you for your Info? – GJPD Jan 19 '19 at 06:14
0

you could solve this by means of a Converter that checks whether you should hide or show the actual Text.
By the use of a MultiValueConverter we can pass in both the original text and a bool which specifies whether we should hide or show it. The return value then is either the actual text or the hidden text:

public class PasswordToHiddenCharactersConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length != 2)
        {
            return string.Empty;
        }

        var passwordText = (string)values[0];
        var hidePassword = (bool)values[1];

        if (hidePassword)
        {
            return string.Empty.PadRight(passwordText.Length, '*');
        }

        return passwordText;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return new[] { value };
    }
}

This then can be used in the XAML to bind the text of the TextBox and it will display correctly depending on the value of the CheckBox:

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

<StackPanel>
    <CheckBox x:Name="HidePasswordBox" Content="Hide Password" />
    <TextBox >
        <TextBox.Text>
            <MultiBinding Converter="{StaticResource PasswordToHiddenCharactersConverter}" UpdateSourceTrigger="PropertyChanged">
                <Binding Path="Password" />
                <Binding ElementName="HidePasswordBox" Path="IsChecked" />
            </MultiBinding>
        </TextBox.Text>
    </TextBox>
</StackPanel>

"Password" is the property name in our ViewModel, for the CheckBox we can directly bind it from within the xaml wihtout having to go via the ViewModel

huserben
  • 1,034
  • 1
  • 10
  • 19
  • If I type in a password, then hide it, and then type more of the password, the second part is shown while the first part is hidden. – redcurry Jan 21 '19 at 15:52
  • @redcurry You're right, this is due to the missing "UpdateSourceTrigger" in the Multibinding. I updated the code snippet with this and that should solve that problem – huserben Jan 21 '19 at 16:40