WPF PasswordBox Binding

  • WPF MVVM
  • .NET 5–6

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    WPF PasswordBox Binding

    Hi,

    ich habe ein kleines Problem mit der PasswordBox, die Property Password ist keine DependencyProperty und kann deswegen nicht gebunden werden. In WPF kann ich auch nicht einfach eine TextBox nehmen, weil die keine PasswordChar-Property wie in Forms hat. Muss ich AttachedProperties nehmen um das RoutedEvent PasswordChanged nutzen zu können(Event abonieren und Command bei Bedarf ausführen), oder haben wir dafür auch eine einfache Möglichkeit in WPF?
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Ich hatte vor Jahren so etwas zusammengebastelt:

    XML-Quellcode

    1. <Window x:Class="LogInDialog"
    2. ...
    3. xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    4. ...
    5. >
    6. ...
    7. <PasswordBox Name="myPasswordBox" Margin="0,1,0,1" BorderBrush="Blue" BorderThickness="1"
    8. IsEnabled="{Binding EnabledPassword}"
    9. Background="{Binding ColorPasswordBox}">
    10. <i:Interaction.Triggers>
    11. <i:EventTrigger EventName="LostMouseCapture">
    12. <cmd:EventToCommand Command="{Binding LogIn.cmdLostMouseCaptured, Source={StaticResource Locator}}"
    13. CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type PasswordBox}}}"
    14. PassEventArgsToCommand="True" />
    15. </i:EventTrigger>
    16. <i:EventTrigger EventName="PasswordChanged">
    17. <cmd:EventToCommand Command="{Binding LogIn.cmdPasswordChanged, Source={StaticResource Locator}}"
    18. CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type PasswordBox}}}"
    19. PassEventArgsToCommand="True" />
    20. </i:EventTrigger>
    21. </i:Interaction.Triggers>
    22. </PasswordBox>

    Dazu brauchst du den Namespace System.Windows.Interactivity
    Ich hoffe es hilft dir...
    Hey, leider scheint das nicht mehr aktuell zu sein. Man muss nun wohl das NugetPacket Microsoft.Xaml.Behaviour.Wpf installieren, sonst tritt ein Fehler ein, das diese InterActivity Dings nicht im namespace zu finden ist. Der Fehler war dann mit dem Nuget Packet weg. Bin nun am rätseln, was cmd für ein Xml-Namespace ist.

    Bin jetzt aber überlegen, ob ich in meiner WPF-Basics-Bibliothek anfange solche Klassen mit AttachedProperties zu sammeln, darauf mache ich eh immer einen Verweis. Dann brauche ich kein Nuget Packet. Für die Maus-Events hab ich bereits eine drin.

    So ist das zwar nicht Bi-Directional, aber das muss in dem Fall ja nicht.
    Spoiler anzeigen

    XML-Quellcode

    1. <Window x:Class="WpfApp1.MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp1"
    7. mc:Ignorable="d"
    8. Title="MainWindow" Height="450" Width="800">
    9. <Window.DataContext>
    10. <local:MainWindowViewModel/>
    11. </Window.DataContext>
    12. <Grid>
    13. <PasswordBox local:PasswordBoxAttachedProperties.PasswordChangedCommand="{Binding OnPasswordChanged}" />
    14. </Grid>
    15. </Window>


    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using System.Windows.Input;
    7. using System.Windows;
    8. using System.Windows.Controls;
    9. namespace WpfApp1
    10. {
    11. public class PasswordBoxAttachedProperties
    12. {
    13. public static readonly DependencyProperty PasswordChangedCommandProperty = DependencyProperty.RegisterAttached("PasswordChangedCommand", typeof(ICommand), typeof(PasswordBoxAttachedProperties), new PropertyMetadata(new PropertyChangedCallback(PasswordChangedCommandChanged)));
    14. private static void PasswordChangedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    15. {
    16. PasswordBox p = (PasswordBox)d;
    17. p.PasswordChanged += OnPasswordChanged;
    18. }
    19. private static void OnPasswordChanged(object sender, RoutedEventArgs e)
    20. {
    21. PasswordBox p = (PasswordBox)sender;
    22. GetPasswordChangedCommand(p)?.Execute(p.Password);
    23. }
    24. public static void SetPasswordChangedCommand(UIElement uIElement, ICommand command) { uIElement.SetValue(PasswordChangedCommandProperty, command); }
    25. public static ICommand GetPasswordChangedCommand(UIElement uIElement) { return uIElement.GetValue(PasswordChangedCommandProperty) as ICommand; }
    26. }
    27. }


    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Diagnostics;
    4. using System.Linq;
    5. using System.Text;
    6. using System.Threading.Tasks;
    7. namespace WpfApp1
    8. {
    9. public class MainWindowViewModel : Notifyable
    10. {
    11. public RelayCommand OnPasswordChanged { get; set; }
    12. public MainWindowViewModel()
    13. {
    14. OnPasswordChanged = new RelayCommand((o) => true, (o) => Debug.WriteLine(o.ToString()));
    15. }
    16. }
    17. }



    Mal schauen was besser ist. @VB1963 verrätst du mir noch was es mit dem Xml-Namespace cmd auf sich hat? Dann kann ich da noch weiterschauen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Sorry - da habe ich dir was unterschlagen...
    Damals habe ich mit Mvvm-Light gearbeitet, das ist nicht mehr aktuell:

    XML-Quellcode

    1. xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"

    Im View-Model:

    VB.NET-Quellcode

    1. Private Password As String
    2. Public Property cmdPasswordChanged As New RelayCommand(Of PasswordBox)(Sub(obj) Password = obj.Password)​

    Jetzt gibt's das MVVM-Toolkit...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB1963“ ()

    Ich habe jetzt so einiges Probiert, mit dem MVVM Toolkit und auch mit dem Microsoft.Xaml.Behaviours.Wpf. Irgendetwas macht da einen Strich durch die Rechnung. Je nachdem was ich gemacht hab, bekam ich entwder die RoutedEventArgs, eine leeren String(wobei ich den ElementName, ElementType und Path im Binding angegeben habe) oder auch die PasswordBox selbst. Ich konnte also nur wenn die PasswordBox als Argument kam auf das Password zugreifen. Aber dann hätte ich was vonner View im ViewModel, daher lasse ich das. Ich denke ich bleibe erstmal wie oben gezeigt bei der AttachedProperty. Ich danke dir für deine Mühe.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @DTF - Schau mal hier:

    github.com/BornToBeRoot/NETwor…alsSetPasswordDialog.xaml

    XAML Code

    Quellcode

    1. xmlns:interactivity="http://schemas.microsoft.com/xaml/behaviors"


    Quellcode

    1. <PasswordBox x:Name="PasswordBoxPassword" Grid.Column="2" Grid.Row="0" Style="{StaticResource DefaultPasswordBox}" >
    2. <interactivity:Interaction.Behaviors>
    3. <wpfHelpers:PasswordBoxBindingBehavior Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    4. </interactivity:Interaction.Behaviors>
    5. </PasswordBox>


    Code behind (im ViewMode):

    github.com/BornToBeRoot/NETwor…lsSetPasswordViewModel.cs

    C#-Quellcode

    1. private SecureString _password = new SecureString();
    2. /// <summary>
    3. /// Password as secure string.
    4. /// </summary>
    5. public SecureString Password
    6. {
    7. get => _password;
    8. set
    9. {
    10. if (value == _password)
    11. return;
    12. _password = value;
    13. ValidatePassword();
    14. OnPropertyChanged();
    15. }
    16. }


    github.com/BornToBeRoot/NETwor…wordBoxBindingBehavior.cs

    C#-Quellcode

    1. public class PasswordBoxBindingBehavior : Behavior<PasswordBox>
    2. {
    3. protected override void OnAttached()
    4. {
    5. AssociatedObject.PasswordChanged += OnPasswordBoxValueChanged;
    6. }
    7. public SecureString Password
    8. {
    9. get => (SecureString)GetValue(PasswordProperty);
    10. set => SetValue(PasswordProperty, value);
    11. }
    12. public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(SecureString), typeof(PasswordBoxBindingBehavior), new PropertyMetadata(null));
    13. private void OnPasswordBoxValueChanged(object sender, RoutedEventArgs e)
    14. {
    15. var binding = BindingOperations.GetBindingExpression(this, PasswordProperty);
    16. if (binding == null)
    17. return;
    18. var property = binding.DataItem.GetType().GetProperty(binding.ParentBinding.Path.Path);
    19. property?.SetValue(binding.DataItem, AssociatedObject.SecurePassword, null);
    20. }
    21. }
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!