2009-07-08 14 views
16

Witam ludzi stackoverflow. Pracuję z MVVM, mam ViewModel zadzwonić UserViewModel z hasłem własności. W polu View należy umieścić kontrolkę PasswordBox.PasswordBox z MVVM

<PasswordBox x:Name="txtPassword" Password="{Binding Password}" /> 

Ale to xaml nie działa. Jak wykonać wiązanie? Prosimy o pomoc!!

+0

Czy masz pewność, że datacontext okna jest ustawiony na model widoku. Musisz dodać trochę kodu, abyśmy mogli zrozumieć Twój problem. –

+0

DataContext jest w porządku. inne właściwości działają dobrze, ale z PasswordBox nie mogę. – Rangel

Odpowiedz

13

Ze względów bezpieczeństwa właściwość Hasło nie jest właściwością zależności i dlatego nie można jej powiązać. Niestety trzeba wykonać wiązanie w kodzie za staroświecki sposób (zarejestrować OnPropertyChanged imprezy i zaktualizować wartość poprzez kod ...)


ja Szybkie wyszukiwanie doprowadza mnie do this blog post który pokazuje, jak napisać załączoną właściwość, aby obejść problem. To, czy warto to robić, czy nie, zależy jednak naprawdę od niechęci do kodowania.

5

Zawsze można napisać formant, który zawija hasło i dodaje właściwość zależności dla właściwości Hasło.

ja po prostu użyć kodu tyłu, ale jeśli trzeba można zrobić coś takiego:

public class BindablePasswordBox : Decorator 
{ 
    public static readonly DependencyProperty PasswordProperty = 
     DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox)); 

    public string Password 
    { 
     get { return (string)GetValue(PasswordProperty); } 
     set { SetValue(PasswordProperty, value); } 
    } 

    public BindablePasswordBox() 
    { 
     Child = new PasswordBox(); 
     ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged; 
    } 

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e) 
    { 
     Password = ((PasswordBox)Child).Password; 
    } 

} 
+0

Używam podobnego rozwiązania, ale uważam, że warto zarejestrować DependencyProperty z FrameworkPropertyMetadata.BindsTwoWayByDefault, więc nie musisz zadeklarować go w XAML za każdym razem. –

+0

Rozumiem, że jest dość stary, jednak jeśli użyję tej metody, to usunie możliwość ustawienia FontSize i ContentAlignment. Jak sobie z tym poradzić? –

2

Jest problem z BindablePasswordBox. Działa tylko w jednym kierunku, PasswordBox do PasswordProperty. Poniżej znajduje się zmodyfikowana wersja, która działa w obu kierunkach. Rejestruje właściwość PropertyChangedCallback i aktualizuje hasło PasswordBox po wywołaniu. Mam nadzieję, że ktoś uzna to za przydatne.

public class BindablePasswordBox : Decorator 
{ 
    public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox), new PropertyMetadata(string.Empty, OnDependencyPropertyChanged)); 
    public string Password 
    { 
     get { return (string)GetValue(PasswordProperty); } 
     set { SetValue(PasswordProperty, value); } 
    } 

    private static void OnDependencyPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
    { 
     BindablePasswordBox p = source as BindablePasswordBox; 
     if (p != null) 
     { 
      if (e.Property == PasswordProperty) 
      { 
       var pb = p.Child as PasswordBox; 
       if (pb != null) 
       { 
        if (pb.Password != p.Password) 
         pb.Password = p.Password; 
       } 
      } 
     } 
    } 

    public BindablePasswordBox() 
    { 
     Child = new PasswordBox(); 
     ((PasswordBox)Child).PasswordChanged += BindablePasswordBox_PasswordChanged; 
    } 

    void BindablePasswordBox_PasswordChanged(object sender, RoutedEventArgs e) 
    { 
     Password = ((PasswordBox)Child).Password; 
    } 
} 
1

Aby uniknąć sytuacji, w której hasło jest dostępne w pamięci jako zwykły tekst w dowolnym punkcie, podałem wartość jako parametr do mojego polecenia.

<Label>User Name</Label> 
<TextBox Text="{Binding UserName}" /> 
<Label>Password</Label> 
<PasswordBox Name="PasswordBox" /> 
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 16 0 0"> 
    <Button Margin="0 0 8 0" MinWidth="65" 
      Command="{Binding LoginAccept}" 
      CommandParameter="{Binding ElementName=PasswordBox}"> 
     Login 
    </Button> 
    <Button MinWidth="65" Command="{Binding LoginCancel}">Cancel</Button> 
</StackPanel> 

Następnie w moim modelu widoku.

public DelegateCommand<object> LoginAccept { get; private set; } 
public DelegateCommand<object> LoginCancel { get; private set; } 

public LoginViewModel { 
    LoginAccept = new DelegateCommand<object>(o => OnLogin(o), (o) => IsLoginVisible); 
    LoginCancel = new DelegateCommand<object>(o => OnLoginCancel(), (o) => IsLoginVisible); 
} 

private void OnLogin(object o) 
{ 
    var passwordBox = (o as System.Windows.Controls.PasswordBox); 
    var password = passwordBox.SecurePassword.Copy(); 
    passwordBox.Clear(); 
    ShowLogin = false; 
    var credential = new System.Net.NetworkCredential(UserName, password); 
} 

private void OnLoginCancel() 
{ 
    ShowLogin = false; 
} 

Chociaż byłoby sensu, aby zapewnić SecurePassword bezpośrednio od wiązania, to zawsze wydaje się zapewniać pustą wartość. Tak więc to NIE działa:

<Button Margin="0 0 8 0" MinWidth="65" 
      Command="{Binding LoginAccept}" 
      CommandParameter="{Binding ElementName=PasswordBox, Path=SecurePassword}"> 
+0

Doświadczyłem dokładnie tego samego! czy wiesz, dlaczego "SecurePassword bezpośrednio z wiązania" nie działa? – Athafoud

+1

Nie mam pojęcia, poza tym, że istnieje celowe ograniczenie dla tego konkretnego typu.SecurePassword nie jest DependencyProperty, która prawdopodobnie przyczynia się do problemu, ale jest standardową własnością tylko do odczytu. Ale można by pomyśleć, że nadal można go przekazać jako parametr, jeśli nie ma nic innego niż przekazanie całej kontroli. –