2010-04-07 8 views
4

Je crée une application WPF qui utilisera la validation de données IDataErrorInfo, implémentée par mes objets métier. J'ai travaillé avec this demo from a blog post pour comprendre ValidatesOnDataErrors.IDataErrorInfo: Validation lors de la soumission de la page

La démo est une application triviale qui lie deux zones de texte à un objet Contact et implémente la validation IDataErrorInfo, en utilisant ValidatesOnDataErrors=True dans la liaison de données. Pour être valide, une zone de texte doit comporter au moins cinq caractères.

Voici mon problème: dans la démo, la validation est déclenchée chaque fois qu'une zone de texte perd le focus. En effet, les zones de texte s'initialisent à un état non valide (bordures rouges) lors du lancement de l'application. Mon application doit reporter la validation jusqu'à ce que l'utilisateur clique sur le bouton OK pour envoyer la page. À ce moment-là, les zones de texte doivent être validées et mises dans un état d'erreur si elles sont invalides. Alors comment différer la validation sur les zones de texte jusqu'à ce que l'utilisateur clique sur le bouton OK? Merci de votre aide.

Répondre

0

La liaison de données a une propriété UpdateSourceTrigger. Comme son nom l'indique, il indique quand mettre à jour la source de la liaison. Pour la propriété Text, elle est définie par défaut sur LostFocus. Vous pouvez définir cela sur Explicit et appeler la méthode UpdateSource de BindingExpression dans le code. D'un autre côté, vous pouvez également reporter la levée de l'événement PropertyChanged. Cependant, cela ne résoudra pas le problème de la validation au lancement de l'application, je pense. J'espère que cela aide d'une manière ou d'une autre.

+0

C'est une solution partielle - Mes bases de données ne sont pas mises à jour tant que je ne les ai pas soumises. Cependant, j'apprécie l'aide, donc c'est accepté par moi. J'ai détaillé ci-dessous une solution plus compliquée qui permet de synchroniser les liaisons mais qui reporte la validation jusqu'à la soumission de la page. –

7

Merci à Michael pour son aide. Malheureusement, j'ai besoin de liaisons pour rester constamment synchronisé, avec seulement la validation différée. Sinon, la solution de Michael ferait l'affaire. Donc, je suis allé dans une direction légèrement différente. Voici la solution que j'ai finalement mise en place.

Démonstration simple: Commençons par le cas le plus simple: Mes objets métier implémentent IDataErrorInfo; Supposons que je puisse modifier la façon dont il est mis en œuvre. Je donne à chaque objet métier une propriété booléenne supplémentaire, ValidationEnabled, et je modifie l'implémentation IDataErrorInfo pour toujours retourner un résultat nul si cette propriété est fausse.

La démo dont j'ai parlé dans mon article original utilise un objet Contact avec deux propriétés; Prénom et nom. J'ai ajouté une propriété ValidationEnabled et modifié la mise en œuvre IDataErrorInfo ressemble à ceci:

#region IDataErrorInfo Members 

public string Error 
{ 
    get { throw new System.NotImplementedException(); } 
} 

public string this[string columnName] 
{ 
    get 
    { 
     // Initialize 
     string result = null; 

     // Perform validation only if enabled 
     if (ValidationEnabled) 
     { 
      switch (columnName) 
      { 
       // Validate 'First Name' 
       case "FirstName": 
        if (string.IsNullOrEmpty(FirstName)) 
        { 
         result = "First name has to be set"; 
        } 
        else if(FirstName.Length < 5) 
        { 
         result = "First name must be at least five characters"; 
        } 
        break; 

       // Validate "Last Name" 
       case "LastName": 
        if (string.IsNullOrEmpty(LastName)) 
        { 
         result = "Last name has to be set"; 
        } 
        else if (LastName.Length < 5) 
        { 
         result = "Last name must be at least five characters"; 
        } 
        break; 
      } 
     } 

     // Set return value 
     return result; 
    } 
} 

#endregion 

Dans ma version de la démo simple, je me connecter sur le bouton Envoyer à un gestionnaire d'événements dans le code-behind qui permet la validation et actualise les fixations pour les deux zones de texte:

private void OnButtonClick(object sender, RoutedEventArgs e) 
{ 
    var contact = (Contact) DataContext; 
    contact.ValidationEnabled = true; 
    var binding = FirstNameBox.GetBindingExpression(TextBox.TextProperty); 
    binding.UpdateSource(); 
    binding = LastNameBox.GetBindingExpression(TextBox.TextProperty); 
    binding.UpdateSource(); 
} 

Maintenant, les contours rouges n'apparaissent que lorsque j'essaie de soumettre le formulaire.

Monde réel: Dans mon application de production, je ne contrôle pas les objets métier, et je ne peux pas les modifier comme je l'ai fait dans ma démo simple. Ainsi, je crée un encapsuleur simple pass-through pour l'objet métier qui expose les propriétés à databound à la vue et relie ces propriétés aux propriétés correspondantes de l'objet métier encapsulé. L'encapsuleur implémente IDataErrorInfo et contient la propriété ValidationEnabled.

L'implémentation IDataErrorInfo du wrapper renvoie toujours null si la validation n'est pas activée. Si la validation est activée, l'encapsuleur appelle l'implémentation IDataErrorInfo sur l'objet encapsulé et renvoie ce qu'il obtient à partir de là.

Cette approche sera familière à quiconque utilisera le modèle Model-View-ViewModel. Ce que nous faisons est de créer un wrapper de modèle de vue pour un objet métier, ce qui est considéré comme une meilleure pratique MVVM par de nombreux développeurs. Il sépare le problème de l'interface utilisateur (suppression des bordures rouges jusqu'à ce que la page soit soumise) du problème du modèle métier (validation d'objet simple).

De plus, mon application de production n'utilisera pas les gestionnaires d'événements dans le code-behind. Par MVVM, le bouton sera câblé à un ICommand, qui contiendra la logique du gestionnaire OnButtonClick() dans la démo simple. J'espère que cela sera utile à quelqu'un d'autre à la recherche de ce problème sur la route.

+0

Merci pour ça ... ça marche plutôt bien pour moi. – danjarvis

Questions connexes