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

Windows Presentation Foundation Discussion :

Forcer/garder le focus sur le contrôle ayant causé ExceptionValidationRule lors de la validation du binding


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Avril 2007
    Messages
    281
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 281
    Par défaut Forcer/garder le focus sur le contrôle ayant causé ExceptionValidationRule lors de la validation du binding
    Bonjour,

    Je conçois actuellement une application C# / WPF. Je possède une fenêtre avec plusieurs Textboxs. Ces textBoxs sont bindés via WPF à mes propriétés d'une classe.

    Lors qu'un utilisateur saisie une donnée dans ces textboxs, certaines données saisies ont besoins d'être validées, pour cela, j'utilise la validation offerte par WPF (ExceptionValidationRule), qui est d'ailleurs simple à utiliser.

    Si la validation échoue, j'arrive donc à en informer l'utilisateur.

    Mon problème est que je souhaiterai que l'utilisateur ne puisse pas sortir de la zone de saisie si cette dernière à une validation qui échoue, et ce, afin que l'utilisateur efface sa valeur, ou, la remplace par une valeur correcte.

    Je souhaiterai savoir si c'est possible, et comment ?

    Voici mon code C# présentant ma propriété bindée :

    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
     
    public string strEvtType
    {
    	get { return m_strEvtType; }
    	set {
    			m_strEvtType = value;
    			if (m_objEvtCode.ReadEvtTypebyType(m_strEvtType) != 0)
    			{
    				throw new ApplicationException("Error ! : " + m_strEvtType.Trim() + " don't exist");
    			}
    			FirePropertyChangedEvent("strEvtType");
    			FirePropertyChangedEvent("m_objEvtCode.strDes");
     
    		}
    }
    Voilà maintenant mon code XAML

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <TextBox Name="TextBox_TypeEvenement" Grid.Column="1" VerticalAlignment="Center" Height="20" LostFocus="TextBox_TypeEvenement_LostFocus">
      <TextBox.Text>
        <Binding Path="strEvtType">
            <Binding.ValidationRules>
                <ExceptionValidationRule />
            </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
    Et voilà maintenant mon Template XAML avec la validation

    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
     
    <Style TargetType="{x:Type TextBox}">
    	<Setter Property="Validation.ErrorTemplate">
    		<Setter.Value>
    			<ControlTemplate>
    				<DockPanel  LastChildFill="False">
    					<TextBlock DockPanel.Dock="Right"
    					Foreground="red"
    					FontSize="9pt"
    					Text="{Binding ElementName=MyAdorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
    					</TextBlock>
    					<Border BorderBrush="Red" BorderThickness="1">
    						<AdornedElementPlaceholder Name="MyAdorner" />
    					</Border>
    				</DockPanel>
    			</ControlTemplate>
    		</Setter.Value>
    	</Setter>
    </Style>
    Je vous remercie d'avance tous pour votre lecture

    Bien cordialement,


    Nixeus

  2. #2
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    351
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 351
    Par défaut
    Il n'y a pas de possibilité (à ma connaissance) d'empêcher la sortie du champ s'il n'est pas rempli en utilisant la validation sous cette forme.

    Rien ne t'empêche par contre d'utiliser la validation afin de mettre en valeur les champs mal remplis et d'implémenter correctement la méthode "CanExecute" de la ICommand qui sera bindé sur ton bouton de validation du formulaire.

    C'est plutôt comme cela que l'on procède en XAML/C# (que ça soit Silverlight ou WPF). C'est un peu moisi en termes d'ergonomie de bloquer l'utilisateur sur un champ, notamment si il veut pouvoir annuler sa saisie et quitter le formulaire.

  3. #3
    Membre éclairé
    Inscrit en
    Avril 2007
    Messages
    281
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 281
    Par défaut
    Bonjour et merci de ta réponse.
    Aurais tu un lien ou un petit exemple sympa mettant en œuvre ta solution ? Car je ne la connais pas en fait

    Merci

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    351
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 351
    Par défaut
    J'imagine que tu dois avoir un bouton du genre "Valider" pour sauvegarder ton formulaire ?

    Vu que tu as l'air d'utiliser le pattern MVVM, il faut savoir que les Command de tes contrôles de validation comme les Button doivent être bindés à des ICommand qui sont présents dans ton ViewModel.
    ICommand est composé de deux méthodes qui sont
    -CanExecute
    -Execute

    La première est utilisée pour activer/désactiver le bouton (ou n'importe quel DependencyObject possédant la DependencyProperty "Command") en fonction de la valeur booléenne renvoyée par celle-ci. En gros, si ta méthode CanExecute renvoie "True", ton bouton sera cliquable, sinon il sera grisé.
    La deuxième correspond au code qui sera exécuté par ton bouton (équivaut à ce que tu mettrais dans l'évènement Click sauf qu'ici tu seras dans le ViewModel et non pas dans le Code Behind de ta View)

    Il y a plusieurs implémentations de ICommand qui existent déjà (pas besoin de t'embêter à la recoder). Tu en as sur nugget ou bien dans des frameworks du style Prism ou MVVM Light.
    Tu trouveras le DelegateCommand de Prism ou la RelayCommand de Josh Smith.


    En général je procède comme suit
    Code c# : 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
            private string _Nom;
            public string Nom
            {
                get { return _Nom; }
                set
                {
                    _Nom = value;
     
                    if (IsStringNullOrEmpty(value))
                        throw new ApplicationException("Le nom est un champ obligatoire.");
     
     
                    this.NotifyPropertyChanged("Nom");
                }
            }
     
            private string _Prenom;
            public string Prenom
            {
                get { return _Prenom; }
                set
                {
                    _Prenom = value;
     
                    if (IsStringNullOrEmpty(value))
                        throw new ApplicationException("Le prénom est un champ obligatoire.");
     
                    this.NotifyPropertyChanged("Prenom");
                }
            }
     
            private string _Ville;
            public string Ville
            {
                get { return _Ville; }
                set
                {
                    _Ville = value;
                    this.NotifyPropertyChanged("Ville");
                }
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(String propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (null != handler)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }
     
            private ICommand _SaveCommand;
            public ICommand SaveCommand
            {
                get
                {
                    if (_SaveCommand == null)
                        _SaveCommand = new RelayCommand(SaveCommandExecute, SaveCommandCanExecute);
     
                    return _SaveCommand;
                }
            }
     
            private void SaveCommandExecute(object parameter)
            {
                //Enregistrement des données
                MessageBox.Show("Personne sauvegardée");
            }
     
            private bool SaveCommandCanExecute(object parameter)
            {
                return !IsStringNullOrEmpty(this.Nom) && !IsStringNullOrEmpty(this.Prenom);
            }
     
            private bool IsStringNullOrEmpty(string sValue)
            {
                return sValue == null || string.IsNullOrEmpty(sValue.Trim());
            }

    Code xaml : 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
    <Window.Resources>
            <Style TargetType="Control" x:Key="BaseStyle">
                <Setter Property="Margin" Value="5" />
            </Style>
            <Style TargetType="TextBox" BasedOn="{StaticResource BaseStyle}" />
            <Style TargetType="TextBlock">
                <Setter Property="Margin" Value="5" />
                <Setter Property="VerticalAlignment" Value="Center" />
            </Style>
            <Style TargetType="Button" BasedOn="{StaticResource BaseStyle}" />
        </Window.Resources>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Text="Nom*" />
            <TextBlock Text="Prénom*" Grid.Row="1" />
            <TextBlock Text="Ville" Grid.Row="2" />
            <TextBox Grid.Column="1">
                <TextBox.Text>
                    <Binding Path="Nom" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                        <Binding.ValidationRules>
                            <ExceptionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
            <TextBox Grid.Row="1" Grid.Column="1">
                <TextBox.Text>
                    <Binding Path="Prenom" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                        <Binding.ValidationRules>
                            <ExceptionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>
            </TextBox>
            <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Ville, Mode=TwoWay}" />
     
            <Button Height="25" Command="{Binding SaveCommand}" Content="Valider" Grid.Row="4" Grid.ColumnSpan="2" />
     
        </Grid>

    Voilà un petit sample.

    C'est très simplifié, tu peux faire des choses plus complexes évidemment, mais si ça ça te suffit c'est déjà bien.

  5. #5
    Membre éclairé
    Inscrit en
    Avril 2007
    Messages
    281
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 281
    Par défaut
    Merci de ta réponse,

    Je suis débutant sous WPF et je n'utilise pas MVVM, j'ai vraiment fait un projet WPF simple sans créer de MVVM.

    Par conséquent j'ai peur que ton sample code soit hardus pour moi

    Voilà ce que je tente de faire :

    Mon bouton de validation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    <Button Template="{StaticResource BoutonRessourcesTpl}" Command="Save">
    	<Button.CommandBindings>
    		<CommandBinding Command="Save"  Executed="Save_Executed" CanExecute="Save_CanExecute"/>
    	</Button.CommandBindings>
    	<Image Source= "Toolbar_Valider.png" Height="16"/>
    </Button>
    Mon code behind

    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
     
            private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
            {
            }
     
            private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
            {
                e.CanExecute = IsValid(sender as DependencyObject);
            }
     
            private bool IsValid(DependencyObject obj)
            {
                // The dependency object is valid if it has no errors, 
                //and all of its children (that are dependency objects) are error-free.
                return !Validation.GetHasError(obj) &&
                    LogicalTreeHelper.GetChildren(obj)
                    .OfType<DependencyObject>()
                    .All(child => IsValid(child));
            }
    J'ai du mal pour la suite....
    Comment et ou mettre mon code qui permet de faire l'enregistrement dans la bdd ?

    Merci à toi

  6. #6
    Membre éclairé
    Inscrit en
    Avril 2007
    Messages
    281
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 281
    Par défaut
    Quelqu'un pourrait me filer un ti coup de pouce s'il vous plait pour mon avant dernier message ? Merci

Discussions similaires

  1. Garder le focus sur le dernier enregistrement
    Par Nacera dans le forum IHM
    Réponses: 4
    Dernier message: 28/05/2008, 09h53
  2. Garder le focus sur une CListCtrl
    Par shawn12 dans le forum MFC
    Réponses: 10
    Dernier message: 24/01/2008, 15h24
  3. Garder le focus sur une popup
    Par identifiant_bidon dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 09/11/2007, 17h12
  4. Réponses: 2
    Dernier message: 27/12/2006, 16h04
  5. [C#]garder le focus sur un node d'un treeview
    Par Blo0d4x3 dans le forum Windows Forms
    Réponses: 3
    Dernier message: 09/05/2006, 21h23

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