2009-07-08 16 views
16

Hola gente stackoverflow. Estoy trabajando con MVVM, tengo ViewModel llamo UserViewModel con una contraseña de propiedad. En el Ver tener un control PasswordBox.PasswordBox con MVVM

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

Pero este xaml no funciona. ¿Cómo se hace el enlace? ¡¡Ayuda por favor!!

+0

¿Se ha asegurado de que el contexto de datos de la ventana esté configurado en el modelo de vista. Necesitas publicar más código para que podamos entender tu problema. –

+0

DataContext está bien. otras propiedades funcionan bien, pero con PasswordBox no puedo. – Rangel

Respuesta

13

Por razones de seguridad, la propiedad Contraseña no es una propiedad de dependencia y, por lo tanto, no puede vincularse a ella. Por desgracia que necesita para llevar a cabo la unión en el código detrás de la manera antigua (registro para el evento OnPropertyChanged y actualizar el valor a través de código ...)


I búsqueda rápida me lleva a this blog post que muestra cómo escriba una propiedad adjunta para eludir el problema. Si esto vale la pena o no, realmente depende de tu aversión al código subyacente.

5

Siempre puede escribir un control que envuelve la Contraseña y agrega una propiedad de dependencia para la propiedad Contraseña.

me acaba de utilizar código detrás, pero si tiene que usted puede hacer algo como:

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

Uso una solución similar, pero me parece útil registrar DependencyProperty con FrameworkPropertyMetadata.BindsTwoWayByDefault para que no tenga que declararla en el XAML cada vez. –

+0

Entiendo que esto es bastante antiguo; sin embargo, si uso este método, se elimina la posibilidad de establecer FontSize y ContentAlignment. ¿Cómo puedo evitar esto? –

2

Hay un problema con el BindablePasswordBox. Solo funciona en una dirección, PasswordBox a PasswordProperty. A continuación se muestra una versión modificada que funciona en ambas direcciones. Registra un PropertyChangedCallback y actualiza la Contraseña PasswordBox cuando se llama. Espero que alguien lo encuentre útil.

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

Para evitar tener la contraseña disponible en la memoria como texto sin formato en cualquier punto, proporciono el valor como un parámetro para mi comando.

<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> 

Entonces, en mi modelo de vista.

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; 
} 

Mientras que tendría sentido para proporcionar la SecurePassword directamente de la unión, siempre parece proporcionar un valor vacío. Entonces esto NO funciona:

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

¡He experimentado exactamente lo mismo! ¿Sabes por qué 'SecurePassword directamente del enlace' no funciona? – Athafoud

+1

No tengo ni idea, además de que haya una restricción intencional para ese tipo específico.SecurePassword no es una DependencyProperty que probablemente contribuya al problema, pero es una propiedad de solo lectura estándar. Pero uno pensaría que aún podría pasarlo como un parámetro si nada más que pasar el control completo. –