2009-11-18 13 views

risposta

44

È possibile utilizzare le NoteAnnotazioni.classe di convalida, come descritto qui:

http://johan.driessen.se/archive/2009/11/18/testing-dataannotation-based-validation-in-asp.net-mvc.aspx

Ma se si sta utilizzando una classe "compagno" per i metadati, è necessario registrare questo fatto prima di convalidare, come descritto qui:

http://forums.silverlight.net/forums/p/149264/377212.aspx

TypeDescriptor.AddProviderTransparent(
    new AssociatedMetadataTypeTypeDescriptionProvider(typeof(myEntity), 
    typeof(myEntityMetadataClass)), 
    typeof(myEntity)); 

List<ValidationResult> results = new List<ValidationResult>(); 
ValidationContext context = new ValidationContext(myEntity, null, null) 
bool valid = Validator.TryValidateObject(myEntity, context, results, true); 

[aggiunto il seguente per rispondere al commento di Shimmy]

Ho scritto un metodo generico per implementare la logica di cui sopra, in modo che qualsiasi oggetto può chiamare:

// If the class to be validated does not have a separate metadata class, pass 
// the same type for both typeparams. 
public static bool IsValid<T, U>(this T obj, ref Dictionary<string, string> errors) 
{ 
    //If metadata class type has been passed in that's different from the class to be validated, register the association 
    if (typeof(T) != typeof(U)) 
    { 
     TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T)); 
    } 

    var validationContext = new ValidationContext(obj, null, null); 
    var validationResults = new List<ValidationResult>(); 
    Validator.TryValidateObject(obj, validationContext, validationResults, true); 

    if (validationResults.Count > 0 && errors == null) 
     errors = new Dictionary<string, string>(validationResults.Count); 

    foreach (var validationResult in validationResults) 
    { 
     errors.Add(validationResult.MemberNames.First(), validationResult.ErrorMessage); 
    } 

    if (validationResults.Count > 0) 
     return false; 
    else 
     return true; 
} 

In ogni oggetto che deve essere convalidato, aggiungo una chiamata a questo metodo:

[MetadataType(typeof(Employee.Metadata))] 
public partial class Employee 
{ 
    private sealed class Metadata 
    { 
     [DisplayName("Email")] 
     [Email(ErrorMessage = "Please enter a valid email address.")] 
     public string EmailAddress { get; set; } 
    } 

    public bool IsValid(ref Dictionary<string, string> errors) 
    { 
     return this.IsValid<Employee, Metadata>(ref errors); 
     //If the Employee class didn't have a buddy class, 
     //I'd just pass Employee twice: 
     //return this.IsValid<Employee, Employee>(ref errors); 
    } 
} 
+0

Ho classi gazillion correlate a MD, hai qualche idea su come associarlo al MD in modo dinamico, ma voglio farlo su richiesta, cioè solo quando sto per usare questa classe (o la sua validazione) e solo una volta. – Shimmy

+0

@Shimmy: vedere sopra. –

+0

grazie! BTW, non c'è bisogno di contrassegnare il dizionario come 'ref', dal momento che non cambierete comunque il riferimento, basta accedere alle sue proprietà. – Shimmy

0

Utilizzare una "classe compagno". Numero 4 in this how-to.

+0

Il collegamento che hai fornito non è applicativo in WPF, penso di averlo menzionato nel mio post. – Shimmy

4

Penso che ciò che manca alla risposta di Craigs è come verificare effettivamente se ci sono errori di validazione. Questo è DataAnnotation convalida corridore scritto da Steve Sanderson per chi vuole correre controllo di convalida a livello di deferente poi di presentazione (http://blog.codeville.net/category/xval/, il codice è in progetto di esempio):

public static IEnumerable<ErrorInfo> GetErrors(object instance) 
{ 
    var metadataAttrib = instance.GetType().GetCustomAttributes 
     (typeof(MetadataTypeAttribute), true). 
      OfType<MetadataTypeAttribute>().FirstOrDefault(); 
    var buddyClassOrModelClass = 
     metadataAttrib != null ? 
     metadataAttrib.MetadataClassType : 
     instance.GetType(); 
    var buddyClassProperties = TypeDescriptor.GetProperties 
     (buddyClassOrModelClass).Cast<PropertyDescriptor>(); 
    var modelClassProperties = TypeDescriptor.GetProperties 
     (instance.GetType()).Cast<PropertyDescriptor>(); 

    return from buddyProp in buddyClassProperties 
      join modelProp in modelClassProperties 
       on buddyProp.Name equals modelProp.Name 
      from attribute in buddyProp.Attributes. 
       OfType<ValidationAttribute>() 
      where !attribute.IsValid(modelProp.GetValue(instance)) 
      select new ErrorInfo(buddyProp.Name, 
       attribute.FormatErrorMessage(string.Empty), instance); 
} 

io non sono a conoscenza di WPF (non è sicuro se c'è una soluzione pronta per te per la domanda), ma forse puoi usarla.

Inoltre, ci sono alcuni commenti sul suo blog che in alcuni casi non riesce a valutare correttamente la regola di convalida, ma non ha mai fallito.

+0

In WPF, deve essere attivato per modifica della proprietà. – Shimmy

+0

Questo è un modo interessante per realizzarlo - Potrei rivedere la mia versione (sopra) con alcune di queste idee. –

1

ho avuto la stessa domanda ed ha trovato le seguenti idee:

3

Potresti essere interessato alla BookLibrary applicazione di esempio del WPF Application Framework (WAF). Fa esattamente quello che stai chiedendo: using DataAnnotations in WPF & Entity Framework.

Problemi correlati