IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Silverlight Discussion :

Validation en Silverlight [Débutant]


Sujet :

Silverlight

  1. #1
    Membre confirmé
    Inscrit en
    Mars 2010
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 57
    Par défaut Validation en Silverlight
    Bonjour à tous,

    Dans le cadre d'une application, je rencontre un problème assez compliqué . Je vous expose le problème

    Nous avons une partie Web Service WCF (que l'on ne peux pas toucher sauf pour des ajouts) qui nous renvoie un objet qui se présente un peu comme ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    [DataContract]
    public WCFContract
    {
        [DataMember]
        public string Name {get; set}
     
        [DataMember]
        public WCFCell Comment {get; set}
     
        [DataMember]
        public ObservableCollection<Rule> Rules {get; set}
    }
     
    [DataContract]
    public WCFCell
    {
        [DataMember]
        public int Id {get; set}
        [DataMember]
        public string Value {get; set}
    }
     
    [DataContract]
    public class Rule
    {
        [DataMember]
        public string PropertyName { get; set; }
     
        [DataMember]
        public ValidationType ValidationType { get; set; }
     
        [DataMember]
        public bool IsRequired { get; set; }
     
        [DataMember]
        public string Message { get; set; }
    }
    La classe WCFContract étant la classe parent de plusieurs autres classes du service.

    Coté Silverlight, nous devons faire un ViewModel générique pour stocker notre WCFContract, l'afficher et faire de la validation coté client.

    En me basant sur des codes déjà exisant sur le net, je suis arrivé à quelque chose comme ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
     
    public class ValidationViewModel<TModel> : INotifyPropertyChanged, INotifyDataErrorInfo
            where TModel : WCFContract
        {
            #region Fields
     
            private readonly List<PropertyValidation<TModel>> _validations = new List<PropertyValidation<TModel>>();
            private Dictionary<string, List<string>> _errorMessages = new Dictionary<string, List<string>>();
     
            private TModel _model;
     
            #endregion
     
            public TModel Model
            {
                get { return _model; }
                set { SetModel(value); }
            }
     
            private void SetModel(TModel value)
            {
                if (value != null)
                {
                    CreateValidation(value.Rules);
                    if(_model != value)
                    {
                        _model = value;
                        //On s'abonne au PropertyCHanged de tous les descendant
                        NotifyPropertyChangedHelper.SetupPropertyChanged(_model, (s, e) => { ValidateProperty(s, e.PropertyName); });
                        OnPropertyChanged("Model")
                    }
                }
            }
     
            protected ValidationViewModel()
            {
                PropertyChanged += (s, e) => { if (e.PropertyName != "HasErrors") ValidateProperty(s, e.PropertyName); };
            }
     
            private void CreateValidation(ObservableCollection<Rule> rules)
            {
                if (rules == null || rules.Count == 0)
                    return;
     
                ValidationBase<TModel> valid = null;
     
                foreach (var rule in rules)
                {
                    var validation = AddValidationFor(rule.PropertyName);
     
                    switch (rule.ValidationType)
                    {
                        case ValidationType.String:
                            var sr = rule as StringRule;
                            if (sr != null)
                            {
                                valid = new StringValidation<TModel>(sr.MinLength, sr.MaxLength);
                                valid.PropertyName = rule.PropertyName;
                                validation.When(valid.GetCompareFunction())
                                    .Show(sr.Message);
                            }
                            break;
                    }
                }
            }
     
            #region INotifyDataErrorInfo
     
            public IEnumerable GetErrors(string propertyName)
            {
                if (_errorMessages.ContainsKey(propertyName))
                    return _errorMessages[propertyName];
     
                return new string[0];
            }
     
            public bool HasErrors
            {
                get { return _errorMessages.Count > 0; }
            }
     
            public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged = delegate { };
     
            private void OnErrorsChanged(string propertyName)
            {
              ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
            }
     
            #endregion
     
            protected PropertyValidation<TModel> AddValidationFor(Expression<Func<object>> expression)
            {
                return AddValidationFor(ExpressionHelper.GetPropertyName(expression));
            }
     
            protected PropertyValidation<TModel> AddValidationFor(string propertyName)
            {
                var validation = new PropertyValidation<TModel>(propertyName);
                _validations.Add(validation);
     
                return validation;
            }
     
            protected void AddAllAttributeValidators()
            {
                PropertyInfo[] propertyInfos = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
     
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    Attribute[] custom = Attribute.GetCustomAttributes(propertyInfo, typeof(ValidationAttribute), true);
                    foreach (var attribute in custom)
                    {
                        var property = propertyInfo;
                        var validationAttribute = attribute as ValidationAttribute;
     
                        if (validationAttribute == null)
                            throw new NotSupportedException("validationAttribute variable should be inherited from ValidationAttribute type");
     
                        string name = property.Name;
     
                        var displayAttribute = Attribute.GetCustomAttributes(propertyInfo, typeof(DisplayAttribute)).FirstOrDefault() as DisplayAttribute;
                        if (displayAttribute != null)
                        {
                            name = displayAttribute.GetName();
                        }
     
                        var message = validationAttribute.FormatErrorMessage(name);
     
                        AddValidationFor(propertyInfo.Name)
                            .When(x =>
                            {
                                var value = property.GetGetMethod().Invoke(this, new object[] { });
                                var result = validationAttribute.GetValidationResult(value,
                                                                        new ValidationContext(this, null, null) { MemberName = property.Name });
                                return result != ValidationResult.Success;
                            })
                            .Show(message);
     
                    }
                }
            }
     
            public void ValidateAll()
            {
                var propertyNamesWithValidationErrors = _errorMessages.Keys;
     
                _errorMessages = new Dictionary<string, List<string>>();
     
                _validations.ForEach(PerformValidation);
     
                var propertyNamesThatMightHaveChangedValidation =
                    _errorMessages.Keys.Union(propertyNamesWithValidationErrors).ToList();
     
                propertyNamesThatMightHaveChangedValidation.ForEach(OnErrorsChanged);
     
                OnPropertyChanged("HasErrors");
            }
     
            public void ValidateProperty(object sender, Expression<Func<object>> expression)
            {
                ValidateProperty(sender, ExpressionHelper.GetPropertyName(expression));
            }
     
            private void ValidateProperty(object sender, string propertyName)
            {
                _errorMessages.Remove(propertyName);
     
                _validations.Where(v => v.PropertyName == propertyName).ToList().ForEach(PerformValidation);
                OnErrorsChanged(propertyName);
                OnPropertyChanged("HasErrors");
            }
     
            private void PerformValidation(PropertyValidation<TModel> validation)
            {
                if (validation.IsInvalid((TModel)this.Model))
                {
                    AddErrorMessageForProperty(validation.PropertyName, validation.GetErrorMessage());
                }
            }
     
            private void AddErrorMessageForProperty(string propertyName, string errorMessage)
            {
                if (_errorMessages.ContainsKey(propertyName))
                {
                    _errorMessages[propertyName].Add(errorMessage);
                }
                else
                {
                    _errorMessages.Add(propertyName, new List<string> { errorMessage });
                }
            }
     
            #region INotifyPropertyChanged
     
            public event PropertyChangedEventHandler PropertyChanged;
     
            protected virtual void OnPropertyChanged(string propertyName)
            {
                PropertyChanged.UISafeInvoke(this, new PropertyChangedEventArgs(propertyName));
            }
     
            #endregion
        }
    et pour mon affichage, j'ai

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <DataTemplate DataType="vm:ViewModelTest">
    		<StackPanel DataContext="{Binding Model, UpdateSourceTrigger=PropertyChanged}">
    			<TextBox Text="{Binding Comment.Value, Mode=TwoWay, 
                            ValidatesOnNotifyDataErrors=True, ValidatesOnExceptions=True, ValidatesOnDataErrors=True, NotifyOnValidationError=True,
                            UpdateSourceTrigger=PropertyChanged}" Width="200"/>
            </StackPanel>
        </DataTemplate>
    Ma partie validation se fait bien: j'ai bien le message d'erreur qui est créée et ajouter si ma méthode de comparaison me retourne true. Jusque là, je suis bon. Seul problème, ça n'affiche pas le tooltip et la bordure indiquant qu'il y a une erreur sur le champs concerné

    D'après ce que j'ai compris (je suis vraiment débutant sur cette partie ), il faudrait que mon objet WCFContract implément INotifyDataErrorInfo pour que cela marche, seul problème, cette objet est généré par le service référence vers notre WCF service

    Auriez vous des pistes à me proposer ou peut être une idée brillante qui m'aidera?

    Merci d'avance de l'aide que vous pourrez m'apportez

  2. #2
    Membre éprouvé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    116
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2012
    Messages : 116
    Par défaut
    Pour le tooltip, tu as tenté un truc de ce genre là?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ToolTipService.SetToolTip(TonChamp, "Ton text");

    et la bordure indiquant qu'il y a une erreur sur le champs concerné
    Par la tu veux dire, une vignette qui afficherait du texte à côté du champ, en plus du tooltip?

    Il y a sans doute mieux, mais tu peux ajouter un textblock invisible, et le rendre visible quand il y a une erreur, et y mettre du texte.

    Mon poste constitue une solution de secours alternative, ne maitrisant pas cet environnement au mieux, en attendant que quelqu'un puisse t'aider au mieux.

    Cela pourra toujours dépanner.

  3. #3
    Membre confirmé
    Inscrit en
    Mars 2010
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Mars 2010
    Messages : 57
    Par défaut
    Merci beaucoup de ta réponse .

    J'ai trouvé une autre solution au final . J'ai créé un composant héritant de ContentControl qui lorsque l'event ErrorsChanged est levé cherche un composant fils qui est bindé à la propriété concernée et ajoute un Adorner sur le composant.

    C'est un peu tordu mais l'essentiel est que ça marche :p

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Validation clé étrangère et migration à silverlight 5
    Par chrisdot dans le forum Silverlight
    Réponses: 2
    Dernier message: 15/12/2011, 14h50
  2. Validation des données silverlight 3
    Par rimenis dans le forum Silverlight
    Réponses: 2
    Dernier message: 19/04/2011, 14h24
  3. Silverlight Classe partielle et validation
    Par pas05 dans le forum Silverlight
    Réponses: 4
    Dernier message: 22/02/2010, 19h01
  4. tester si une date est valide
    Par Andry dans le forum Langage
    Réponses: 5
    Dernier message: 17/09/2002, 11h54
  5. [VB6] Evenement validate
    Par grosjej dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 05/09/2002, 15h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo