2013-02-27 12 views
11

Sto provando a fare una convalida per un PasswordBox. Per fare convalide ho seguito questo link, che mostra come convalidare su TextBox.Come convalidare PasswordBox WPF

Il problema si verifica con PasswordBoxes. Siccome è Password non è collegabile per motivi di sicurezza, ho provato a fare un binding seguendo this link (spiegato anche here, per gli utenti CodeProject).

Quindi, a quanto pare, fantastico! Posso bloccare il mio PasswordBox con la sua proprietà Password, quindi posso eseguire il binding con la mia convalida. Ma mi ignora ...

Si tratta di un normale TextBox che io uso e funziona benissimo:

<local:ErrorProvider Grid.Column="1" Grid.Row="2" > 
    <TextBox Width="160" 
      HorizontalAlignment="Left" 
      Name="textBoxUserPass" 
      Text="{Binding Path=Password, UpdateSourceTrigger=Explicit}" /> 
</local:ErrorProvider> 

E questo è il PasswordBox ho cercato di simulare:

<local:ErrorProvider Grid.Column="1" Grid.Row="2" > 
     <PasswordBox Width="160" 
      HorizontalAlignment="Left" 
      Name="textBoxUserPass" 
      local:PasswordBoxAssistant.BindPassword="True" 
      local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, UpdateSourceTrigger=Explicit}" /> 
</local:ErrorProvider> 

Questo è il modo in Ottengo il BindingExpression per ogni TextBox:

BindingExpression beUserName = textBoxUserName.GetBindingExpression(TextBox.TextProperty); 
if (beUserName != null) beUserName.UpdateSource(); 

E questo è come ho capito per la PasswordBox:

BindingExpression bePassword = textBoxUserPass.GetBindingExpression(PasswordBoxAssistant.BoundPassword); 
if (bePassword != null) bePassword.UpdateSource(); 

Se abbiamo fatto alcun errore (definito sulla mia classe di convalida), quando faccio questo:

if (!beUserName.HasError && !bePassword.HasError) 

ogni BindingExpression dovrebbe dire true di false in base alla convalida dell'errore. Ma per il mio PasswordBox non si ottiene mai il valore ... Qualche idea?

+0

Hai provato impostazione ' ValidatesOnDataErrors = True' e 'ValidatesOnExceptions = True' sui tuoi binding? –

+0

Non esiste per 'PasswordBox' ... – Sonhja

+0

Lo fa per la proprietà associata' BoundPassword': 'local: PasswordBoxAssistant.BoundPassword =" {Percorso vincolante = Password, UpdateSourceTrigger = Esplicito, ValidatesOnDataErrors = True, ValidatesOnExceptions = True} "' –

risposta

11

Prova impostazione ValidatesOnDataErrors=True e ValidatesOnExceptions=True sulla rilegatura:

<PasswordBox ... 
    local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, 
     UpdateSourceTrigger=Explicit, 
     ValidatesOnDataErrors=True, 
     ValidatesOnExceptions=True}" 
/> 
1

Per quanto mi ricordo, l'unico modo per aggiungere la convalida su una PasswordBox è lanciare una nuova ValidationException nel setter della proprietà di bind per SecurePassword. PasswordBoxAssistant non ti aiuterà con questo.

+0

Hummm è possibile fornire un esempio o un collegamento? Sembra una soluzione. – Sonhja

+0

Questo è quello che ho trovato in una vecchia app su cui stavo lavorando: public SecureString NewPassword { get { return _newPassword; } set { _newPassword = valore; errore stringa = IsPasswordValid(); if (! String.IsNullOrEmpty (error)) { throw new ValidationException (errore); } } } –

+0

Hummm, proveremo, ma la soluzione esatta è quella pubblicata da Richard Deeming (per questo caso). Ma ci proverò anche questo, visto che ho questo caso particolare anche nel mio codice. – Sonhja

1

Set Mode = TwoWay sul legame

local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,Mode=TwoWay, 
UpdateSourceTrigger=Explicit}" 
2

Un'altra soluzione, senza l'utilizzo di qualsiasi stringa "non protetto" nel mezzo, è quello di adattare il codice Window, qualcosa come questo:

Supponiamo di avere un oggetto MVVM come questo, con convalida WPF usando IDataErrorInfo:

public class MyObject : INotifyPropertyChanged, IDataErrorInfo 
{ 
    ... 
    public SecureString SecurePassword 
    { 
     get 
     { ... } 
     set 
     { 
      ... 
      OnPropertyChanged("SecurePassword"); 
     } 
    } 

    ... 

    string IDataErrorInfo.Error { get { return Validate(null); } } 
    string IDataErrorInfo.this[string columnName] { get { return Validate(columnName); } } 

    private string Validate(string memberName) 
    { 
     string error = null; 
     ... 
     if (memberName == "SecurePassword" || memberName == null) 
     { 
      // this is where I code my custom business rule 
      if (SecurePassword == null || SecurePassword.Length == 0) 
      { 
       error = "Password must be specified."; 
      } 
     } 
     ... 
     return error; 
    } 

} 

E un Xaml Finestra con una PasswordBox come questo:

<PasswordBox Name="MyPassword" PasswordChanged="MyPassword_Changed" ... /> 

Poi, il codice finestra corrispondente come questo innescherà PasswordBox vincolante:

// add a custom DependencyProperty 
public static readonly DependencyProperty SecurePasswordProperty = 
    DependencyProperty.RegisterAttached("SecurePassword", typeof(SecureString), typeof(MyWindow)); 

public MyWindow() 
{ 
    InitializeComponent(); 

    DataContext = myObject; // created somewhere 

    // create a binding by code 
    Binding passwordBinding = new Binding(SecurePasswordProperty.Name); 
    passwordBinding.Source = myObject; 
    passwordBinding.ValidatesOnDataErrors = true; 
    // you can configure other binding stuff here 
    MyPassword.SetBinding(SecurePasswordProperty, passwordBinding); 
} 

private void MyPassword_Changed(object sender, RoutedEventArgs e) 
{ 
    // this should trigger binding and therefore validation 
    ((MyObject)DataContext).SecurePassword = MyPassword.SecurePassword; 
}