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

C# Discussion :

Ajout/Supp/Modif DataGrid sans formulaire


Sujet :

C#

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut Ajout/Supp/Modif DataGrid sans formulaire
    Bonjour à tous,

    Je récupère des données de fichiers .xml afin d'en faire mon ItemSource.
    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
    #region Constructor
            public OperateurDataGridViewModel()
            {
                DataGridSource = new ObservableCollection<object>();
     
                foreach (var res in OperateurProvider.getFolderDataPath())
                {
                    DataGridSource.Add(new Operateur
                    {
                        ID = res.Attribute("ID").Value,
                        Prenom = res.Element("Prenom").Value,
                        Nom = res.Element("Nom").Value,
                        Equipe = res.Element("Equipe").Value,
                        Ligne = res.Element("Ligne").Value,
                        Gap = res.Element("Gap").Value,
                        GapLeader = res.Element("GapLeader").Value,
                        SST = res.Element("SST").Value,
                    });
                }
     
            }
            #endregion Constructor
    Mon modèle associé est celui-ci
    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
    #region Properties
            //Implémenter l'interface INotify sur chaque prop
            public string ID { get; set; }
     
            private string _prenom;
            public string Prenom 
            { 
                get
                {
                    Console.WriteLine($"[test] {_prenom}");
                    return _prenom;
                }
                set
                {
                    _prenom = value;
                    OnPropertyChanged("Prenom");
                }
            }
     
            public string Nom { get; set; }
            public string Equipe { get; set; }
            public string Ligne { get; set; }
            public string Gap { get; set; }
            public string GapLeader { get; set; }
            public string SST { get; set; }
            #endregion Properties
    Je bind sans problème le tout dans ma vue
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <DataGrid Grid.Row="1" Grid.Column="1" AutoGenerateColumns="False" AlternatingRowBackground="LightGray" ItemsSource="{Binding DataGridSource, UpdateSourceTrigger=LostFocus}">
                <DataGrid.Columns>
                    <DataGridTextColumn Width="*" Header="Prenom" Binding="{Binding Prenom}" />
                    <DataGridTextColumn Width="*" Header="Nom" Binding="{Binding Nom}" />
                    <DataGridTextColumn Width="*" Header="Equipe" Binding="{Binding Equipe}" />
                    <DataGridTextColumn Width="*" Header="Ligne" Binding="{Binding Ligne}" />
                    <DataGridTextColumn Width="*" Header="Gap" Binding="{Binding Gap}" />
                    <DataGridTextColumn Width="*" Header="Gap Leader" Binding="{Binding GapLeader}" />
                    <DataGridTextColumn Width="*" Header="SST" Binding="{Binding SST}" />
                </DataGrid.Columns>
     
            </DataGrid>

    Nom : DataGrid.PNG
Affichages : 669
Taille : 19,0 Ko

    Je souhaite pouvoir créer, modifier, supprimer directement des données à partir du dataGrid.
    En parcourant le forum, je suis tombé sur ce poste https://www.developpez.net/forums/d9...-datagridview/

    Tomlev disait (ca doit toujours être d'actualité)
    Pour une liste d'objets c'est un peu plus complexe :
    - les objets de la liste doivent implémenter INotifyPropertyChanged pour déclencher un évènement quand une valeur de propriété change (sinon le DataGridView ne pourra pas le savoir)
    - la liste elle-même doit implémenter IBindingList, pour déclencher un évènement quand la liste change (ajout ou suppression d'éléments). Le plus simple est d'utiliser la classe BindingList<T> qui gère déjà tout ça
    J'ai suivi les conseils (en implémentant l'interface INotify), mais lors de la saisie d'une ligne, je récupère 4 fois la valeur insérée...
    En implémentant IBindingList et la fonction Add c'est la même chose.
    Nom : DataGrid_2.PNG
Affichages : 637
Taille : 26,2 Ko

    Sauriez-vous ce qui cloque ?

    PS : le code est un peu cracra, il sera épuré par la suite

  2. #2
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour

    le code est un peu cracra, il sera épuré par la suite
    il l'est probablement ca doit etre du à la frappe sauvage et pressé.
    Donc à corriger.
    Comme le demontre le code ci-apres tapé calmement.
    1/ class model (dossier Model):
    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
    namespace WpfBinding.Model
    {
        //Implémenter l'interface INotify
        public class ModelBase:INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            //attribut public pour evitet la uplication de code
            public void OnPropertyChanged(string propName)
            {
                PropertyChangedEventHandler h=PropertyChanged;
                if (h != null)
                    h(this, new PropertyChangedEventArgs(propName));
            }
        }
     
     
     
    //l'heritage simplifie la vie
        public class Item:ModelBase
        { 
            #region Properties
            private string _id;
            public string ID 
            { 
                get { return _id;}
                set
                {
                    _id = value;
                    OnPropertyChanged("ID");
                }
            }
            private string _nom;
            public string Nom
            {
                get { return _nom; }
                set
                {
                    _nom = value;
                    OnPropertyChanged("Nom");
                }
            }
            private string _prenom;
            public string Prenom 
            { 
                get { return _prenom;}
                set
                {
                    _prenom = value;
                    OnPropertyChanged("Prenom");
                }
            }
            private int _age;
            public int Age
            {
                get { return _age; }
                set
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
     
     
            #endregion Properties
            public Item()
            {
     
            }
        }
    }
    1/ class provider (dossier Repositry ou dépôt):
    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
    using WpfBinding.Model;
     
    namespace WpfBinding.Repositry
    {
        public class Provider
        {
            private Random rnd=new Random();
     
     // prop avec getter et SETTER
     private ObservableCollection<object> _dataGridSource =null;
            public ObservableCollection<object> DataGridSource  
            { 
                get{ return _dataGridSource ;}
     
          set { _dataGridSource =value; }
            }
            public Provider ()
    	    {
                OperateurDataGridViewModel();
    	    }
            public void OperateurDataGridViewModel()
            {
                _dataGridSource = new ObservableCollection<object>();
     
                for (int i=1 ;i<20 ;i++)
                {
                    _dataGridSource.Add(
                        new Item(){ 
                            ID = i.ToString(),
                            Nom = "Nom"+i.ToString(),
                            Prenom = "Prenom"+i.ToString(),
                            Age=rnd.Next(20,60)
                    });
                }
     
            }
        }
    }
    code xaml du form:
    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
    <Window x:Class="WpfBinding.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <DockPanel Grid.Row="0">
                <Label Margin="5" Content="nb item" />
                <TextBlock  Margin="5" Text="{ Binding DataGridSource.Count }"  VerticalAlignment="Center"/>
            </DockPanel>
            <DataGrid Grid.Row="1" Grid.Column="1" AutoGenerateColumns="False" AlternatingRowBackground="LightGray" 
                      ItemsSource="{Binding DataGridSource,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                       >
                <DataGrid.Columns>
                    <DataGridTextColumn Width="*" Header="ID" Binding="{Binding ID}" />
                    <DataGridTextColumn Width="*" Header="Nom" Binding="{Binding Nom}" />
                    <DataGridTextColumn Width="*" Header="Prenom" Binding="{Binding Prenom}" />
                    <DataGridTextColumn Width="*" Header="Age" Binding="{Binding Age}" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>
    code behind.cs du form:
    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
    using WpfBinding.Repositry;
     
    namespace WpfBinding
    {
        /// <summary>
        /// Logique d'interaction pour MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private Provider provider=new Provider();
            public MainWindow()
            {
                InitializeComponent();
                this.DataContext = provider;
            }
     
     
        }
    }
    Sélectionne une ligne ,supprime là et surveille le Count.
    bon code.

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut
    Tout est bon MABROUKI, je supprime, j'ajoute, je modifie, le counter réagit correctement selon la fonction.

    Ce que je ne comprends pas, c'est comment récupérer les données cellule par cellule de la ligne supprimée/ajoutée/modifiée afin d'ajouter l'élément dans un DB par exemple.

    Beaucoup de tutos et vidéos traitent les actions via un formulaire. Mais c'est pas très propre visuellement. (ça m'embêterait de devoir créer un textblock par colonne puis un bouton Add,Remove, Modify. Ca va faire lourd dans l'appli)
    Ca doit bien pouvoir se faire directement via le datagrid...Ce control est puissant.
    Je suis convaincu qu'on puisse le faire, mais je n'arrive pas à trouver l'event qui gère ça.

  4. #4
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Citation Envoyé par MABROUKI Voir le message
    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
     
    namespace WpfBinding.Model
    {
        //Implémenter l'interface INotify
        public class ModelBase:INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            //attribut public pour evitet la uplication de code
            public void OnPropertyChanged(string propName)
            {
                PropertyChangedEventHandler h=PropertyChanged;
                if (h != null)
                    h(this, new PropertyChangedEventArgs(propName));
            }
        }
    Qu'est-ce-que tu veux dire par //attribut public pour evitet la uplication de code ? Si tu parles de la méthode OnPropertyChanged() la mettre protected suffit pour la réutiliser dans les classes filles ; et on peut y rajouter un attribut [CallerMemberName] pour ne pas avoir à fournir explicitement le nom de la propriété.

  5. #5
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    Citation Envoyé par Noxen Voir le message
    Qu'est-ce-que tu veux dire par //attribut public pour evitet la uplication de code ? Si tu parles de la méthode OnPropertyChanged() la mettre protected suffit pour la réutiliser dans les classes filles ; et on peut y rajouter un attribut [CallerMemberName] pour ne pas avoir à fournir explicitement le nom de la propriété.
    Evidemment mais ce choix dépend de zeratec.
    CallerMember n'et pas disponible sous V 2010.

  6. #6
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    Citation Envoyé par zeratec Voir le message
    Tout est bon MABROUKI, je supprime, j'ajoute, je modifie, le counter réagit correctement selon la fonction.

    Ce que je ne comprends pas, c'est comment récupérer les données cellule par cellule de la ligne supprimée/ajoutée/modifiée afin d'ajouter l'élément dans un DB par exemple.


    le control est puissant.
    Je suis convaincu qu'on puisse le faire, mais je n'arrive pas à trouver l'event qui gère ça.
    Ah oui ce control est puissant ,mais plus puissant est l'ObservableCollection<T> qui veille au grain .

    Tu eux faire la m.a.j de ta BD grâce à lui:
    code behind.cs revu du class Provider:
    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
     
    using WpfBinding.Model;
    using System.Collections.Generic;
     
    using System;
    using System.Collections.ObjectModel;
    using WpfBinding.Model;
     
     
    namespace WpfBinding.Repositry
    {
        public class Provider
        {
     
            private Random rnd=new Random();
     
            // prop avec getter et SETTER
            private ObservableCollection<object> _dataGridSource = null;
            public ObservableCollection<object> DataGridSource  
            { 
                get{ return _dataGridSource ;}
                set{  _dataGridSource =value;}
            }
            public Provider ()
    	    {
                _dataGridSource = new ObservableCollection<object>();
                _dataGridSource.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_dataGridSource_CollectionChanged);
                OperateurDataGridViewModel();
    	    }
     
     
            public void OperateurDataGridViewModel()
            {
     
     
                for (int i=1 ;i<20 ;i++)
                {
                    _dataGridSource.Add(
                        new Item(){ 
                            ID = i.ToString(),
                            Nom = "Nom"+i.ToString(),
                            Prenom = "Prenom"+i.ToString(),
                            Age=rnd.Next(20,60)
                    });
                }
     
            }
            void _dataGridSource_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                List<object> l = new List<object>();
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    l.AddRange((List<Item>)e.NewItems);
                    this.AddItems(l);
                }
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
                {
                    l.AddRange((List<object>)e.NewItems);
                    this.DeleteItems(l);
                }
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
                {
                    l.AddRange((List<object>)e.NewItems);
                    this.ModifyItems(l);
                }
            }
            public void AddItems(List<object> itemsToAdd)
            {
                foreach (var item in itemsToAdd)
                {
                    //ton code pour ajout des elements dans source de données
                }
     
            }
            public void DeleteItems(List<object> itemsToDelete)
            {
                foreach (var item in itemsToDelete)
                {
                    //ton code pour suppression des elements dans source de données 
                }
            }
            public void ModifyItems(List<object> itemsToModify)
            {
                foreach (var item in itemsToModify)
                {
                    //ton code pour update des elements dans source de données 
                }
            }
     
        }
    }
    bon code...

  7. #7
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    List<object> l = new List<object>();
                if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    l.AddRange((List<object>)e.NewItems);
                    this.AddItems(l);
                }
    J'ai analysé le code et j'ai parcouru la doc après l'avoir adapté dans ma situation.
    La propriété "NewItems" est en ReadOnly d'après la doc. En effet, lorsque l'on exécute le code l'exception suivante est levée :
    Impossible d'effectuer un cast d'un objet de type 'ReadOnlyList' en type 'System.Collections.Generic.List`1[System.Object]'.
    Je n'arrive pas à trouver comment récupérer la liste de données ajoutées. Sur ce coup, même Google n'est pas mon ami

  8. #8
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Enlève le cast, e.NewItems est une IList mais pas forcément une List<object> ; utilise plutôt e.NewItems.Cast<object>() pour obtenir un type explicite.

  9. #9
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut
    Bonjour,

    J'ai suivi vos conseils MABROUKI et Noxen.
    J'arrive à faire fonctionner la fonction "Delete" (lors de la suppression d'une ligne par un appui de la touche "suppr" du clavier).
    [Persons] ID :5 Firstname : Firstname 5 Lastname : Lastname 5 Age : 49 > removed.
    [Persons] ID :13 Firstname : Firstname 13 Lastname : Lastname 13 Age : 22 > removed.
    J'ai beaucoup plus de mal pour les fonctions "Add" et "Modify".

    Je vous joins le code ainsi que le lien github (si besoin, pour voir les liens des classes)
    https://github.com/Zeratec/Training_WPFMVVM

    J'ai construit un exercice basique pour apprendre à bien manipuler cet outil (DataGrid).

    Voici la classe Vue-Modèle
    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
    namespace Training_WPFMVVM_DataGrid.ViewModels.UserControlViewModels
    {
        public class DataGridViewModel : ViewModelBase
        {
            #region Variable
            private Random rnd = new Random();
            #endregion Variable
     
            #region Constructor
            public DataGridViewModel()
            {
                DataGridSource = new ObservableCollection<object>();
                loadData();
                DataGridSource.CollectionChanged += _dataGridSource_CollectionChanged;
            }
            #endregion Constructor
     
            #region Properties
            private ObservableCollection<object> _dataGridSource = null;
            public ObservableCollection<object> DataGridSource
            {
                get 
                { 
                    return _dataGridSource;
                }
                set 
                { 
                    _dataGridSource = value;
                }
            }
     
            private Person _selectedItem;
            public Person SelectedItem
            {
                get
                {
                    return _selectedItem;
                }
                set
                {
                    _selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                }
            }
            #endregion Properties
     
            #region Public Method
            public void loadData()
            {
                for (int i = 1; i < 20; i++)
                {
                    DataGridSource.Add(new Person()
                    {
                        ID = i.ToString(),
                        Firstname = "Firstname " + i.ToString(),
                        Lastname = "Lastname " + i.ToString(),
                        Age = rnd.Next(20, 60).ToString(),
                    });
                }
            }
     
            private void AddItems(List<object> itemsToAdd)
            {
                foreach (Person item in itemsToAdd)
                {
                    Console.WriteLine($"[Persons]\t" +
                    $"ID :{item.ID}\t " +
                    $"Firstname : {item.Firstname}\t " +
                    $"Lastname : {item.Lastname}\t " +
                    $"Age : {item.Age}\t " +
                    $"> added.");
                }
            }
     
            private void ModifyItems(List<object> itemsToModify)
            {
                foreach (Person item in itemsToModify)
                {
                    Console.WriteLine($"[Persons]\t" +
                    $"ID :{item.ID}\t " +
                    $"Firstname : {item.Firstname}\t " +
                    $"Lastname : {item.Lastname}\t " +
                    $"Age : {item.Age}\t " +
                    $"> modified.");
                }
            }
     
            private void DeleteItems(List<object> itemsToDelete)
            {
                foreach (Person item in itemsToDelete)
                {
                    Console.WriteLine($"[Persons]\t" +
                    $"ID :{item.ID}\t " +
                    $"Firstname : {item.Firstname}\t " +
                    $"Lastname : {item.Lastname}\t " +
                    $"Age : {item.Age}\t " +
                    $"> removed.");
                }
            }
            #endregion Public Method
     
            #region Private Method
            private void _dataGridSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                List<object> list = new List<object>();
     
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        list.AddRange(e.NewItems.Cast<object>().ToList());
                        AddItems(list);
                        break;
     
                    case NotifyCollectionChangedAction.Move:
                        break;
     
                    //Fonction Delete Fonctionne
                    case NotifyCollectionChangedAction.Remove:
                        DeleteItems(e.OldItems.Cast<object>().ToList());
                        break;
     
                    case NotifyCollectionChangedAction.Replace:
                        ModifyItems(e.OldItems.Cast<object>().ToList());
                        break;
     
                    case NotifyCollectionChangedAction.Reset:
                        break;
     
                    default:
                        throw new NotImplementedException();
                }            
            }
            #endregion Private Method
        }
    }
    Les deux problèmes rencontrés sont les suivants :
    1) Lors de l'ajout d'une ligne (remplissage de la "Row" vide en bas du DataGrid), l'event CollectionChanged se rend bien compte que l'action ADD est appelée. Cependant, le programme n'attend pas que la ligne soit complétement rempli avant de rentrer dans la méthode "AddItems".
    La console affiche donc :
    [Persons] ID : Firstname : Lastname : Age : > added.
    2) Lors de la modification d'une ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     if (e.Action == NotifyCollectionChangedAction.Replace)
                {
                    ModifyItems(e.NewItems.Cast<object>().ToList());
                }
    Rien ne se produit. En mettant des points d'arrêts dans le programme je me rends compte que le cas "Replace" n'est pas testée.

    Sauriez-vous m'aiguiller ?

  10. #10
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut
    Citation Envoyé par zeratec Voir le message
    Rien ne se produit. En mettant des points d'arrêts dans le programme je me rends compte que le cas "Replace" n'est pas testée.
    C'est tout à fait normal. En effet, dans la propriété CollectionChanged, si un changement est fait sur un élement déjà existant, l'évènement n'est pas levé.
    Le changement d'un objet existant est de la responsabilité de l'objet, et non de la collection.
    Il faut donc récupérer les changements dans les propriétés de la classe
    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
    #region Properties
            public string ID 
            { 
                get
                {
                    return _id;
                }
                set
                {
                    _id = value;
                    OnPropertyChanged("ID");
                }
            }
     
            public string Firstname
            {
                get
                {
                    return _firstname;
                }
                set
                {
                    _firstname = value;
                    OnPropertyChanged("Firstname");
                }
            }
     
            public string Lastname
            {
                get
                {
                    return _lastname;
                }
                set
                {
                    _lastname = value;
                    OnPropertyChanged("Lastname");
                }
            }
     
            public string Age
            {
                get
                {
                    return _age;
                }
                set
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
            #endregion Properties
    En implémentant l'interface "IEditableObject" dans le model Person.cs et en ajoutant les lignes suivantes (en vert) :
    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
    public class Person : ViewModelBase, IEditableObject
        {
            #region Variable
            private string _id;
            private string _lastname;
            private string _firstname;
            private string _age;
            private bool inTxn = false;
            #endregion Variable
    
            #region Constructor
            public Person()
            {
    
            }
            #endregion Constructor
    
            #region Properties
            public string ID 
            { 
                get
                {
                    return _id;
                }
                set
                {
                    _id = value;
                    OnPropertyChanged("ID");
                }
            }
    
            public string Firstname
            {
                get
                {
                    return _firstname;
                }
                set
                {
                    _firstname = value;
                    OnPropertyChanged("Firstname");
                }
            }
    
            public string Lastname
            {
                get
                {
                    return _lastname;
                }
                set
                {
                    _lastname = value;
                    OnPropertyChanged("Lastname");
                }
            }
    
            public string Age
            {
                get
                {
                    return _age;
                }
                set
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
            #endregion Properties
    
            #region Public Method
            public void BeginEdit() { inTxn = true; }
    
            public void CancelEdit() { }
    
            public void EndEdit()
            {
                if (inTxn)
                {
                    Console.WriteLine($"[Persons]\t" +
                        $"ID :{this.ID}\t " +
                        $"Firstname : {this.Firstname}\t " +
                        $"Lastname : {this.Lastname}\t " +
                        $"Age : {this.Age}\t " +
                        $"> Modified.");
                    inTxn = false;
                }
            }
            #endregion Public Method
    
            #region Private Method
            #endregion Private Method
        }
    J'arrive à récupérer la modification des lignes.

    Il ne reste plus qu'à gérer l'ajout...

    Que pensez-vous de ce raisonnement ?

  11. #11
    Membre Expert
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 941
    Par défaut
    Tu sais que tu pouvais déjà récupérer les propriétés modifiées par l'événement PropertyChanged, puisque ton view model implémente INotifyPropertyChanged ?

  12. #12
    Membre confirmé
    Homme Profil pro
    Ingénieur
    Inscrit en
    Février 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur

    Informations forums :
    Inscription : Février 2015
    Messages : 66
    Par défaut
    La solution de mon précédent post fonctionne, mais le pattern MVVM n'est pas respecté.
    En effet, l'interface de IEditableObject (fonctions BeginEdit(), CancelEdit() et EndEdit()) est appelé par le contrôle directement. Dans ce cas, autant ne pas se prendre la tête et directement travailler dans le code-behind, mais ça ne nous intéresse pas dans ce cas.

    C'est toujours bon de connaître plusieurs solutions et pourquoi l'une est meilleure que l'autre.

    Afin de respecter cette contrainte du pattern MVVM, voilà la solution que j'ai trouvé.
    J'ai abonné chaque item de ma collection à un événement "ItemPropertyChanged".

    La fonction loadData() devient donc :
    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
    public void loadData()
            {
                for (int i = 1; i < 20; i++)
                {
                    DataGridSource.Add(new Person()
                    {
                        ID = i.ToString(),
                        Firstname = "Firstname " + i.ToString(),
                        Lastname = "Lastname " + i.ToString(),
                        Age = rnd.Next(20, 60).ToString(),
                    });
                }
    
                foreach (Person item in DataGridSource)
                {
                    item.PropertyChanged += onPropertyChanged;
                }
            }
    L'événement créé est le suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private void onPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                //Update de la DB
                Console.WriteLine($"[Persons] > Modified\t" +
                    $"ID :{_id}\t " +
                    $"Firstname : {_selectedItem.Firstname}\t " +
                    $"Lastname : {_selectedItem.Lastname}\t " +
                    $"Age : {_selectedItem.Age}.");
            }
    Grâce à cet événement, lorsque l'on modifie une cellule du DataGrid la DB est mise à jour.

    Vient maintenant la fonction d'ajout.
    Lorsque l'on souhaite ajouter une donnée dans la dernière ligne (vide) du DataGrid, voici ce que nous dit le débogueur :
    System.Windows.Data Error: 23 : Cannot convert '{NewItemPlaceholder}' from type 'NamedObject' to type 'Training_WPFMVVM_DataGrid.Models.Person' for 'en-US' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: Conversion de TypeConverter impossible à partir de MS.Internal.NamedObject.
    à System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
    à System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
    à MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'

    System.Windows.Data Error: 7 : ConvertBack cannot convert value '{NewItemPlaceholder}' (type 'NamedObject'). BindingExpression: Path=SelectedItem; DataItem='DataGridViewModel' (HashCode=38240801); target element is 'DataGrid' (Name=''); target property is 'SelectedItem' (type 'Object') NotSupportedException:'System.NotSupportedException: Conversion de TypeConverter impossible à partir de MS.Internal.NamedObject.
    à MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
    à MS.Internal.Data.ObjectTargetConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
    à System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'
    Pour traiter ce sujet, il faut créer un Converter
    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
    namespace Training_WPFMVVM_DataGrid.Services
    {
        public class ConverterService : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return value;
            }
     
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (value != null && string.Equals("{NewItemPlaceholder}", value.ToString(), StringComparison.Ordinal))
                {
                    return null;
                }
                return value;
            }
        }
    }
    Il faut ensuite binder ce converter à la propriété SelectedItem du DataGrid (dans le fichier .xaml)
    Code xaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    <DataGrid Grid.Row="1" Grid.Column="1" AutoGenerateColumns="False" AlternatingRowBackground="LightGray" CanUserAddRows="True" ItemsSource="{Binding DataGridSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedItem, Converter={StaticResource Converter}}">
                <DataGrid.Columns>
                    <DataGridTextColumn Width="*" Header="Firstname" IsReadOnly="False" Binding="{Binding Firstname}" />
                    <DataGridTextColumn Width="*" Header="Lastname" IsReadOnly="False" Binding="{Binding Lastname}" />
                    <DataGridTextColumn Width="*" Header="Age" IsReadOnly="False" Binding="{Binding Age}" />
                </DataGrid.Columns>
            </DataGrid>

    Le code de l'événement CollectionChanged avec la fonction Ajout et Suppression :
    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
    private void _dataGridSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                //Fonction Ajout
                if (e.NewItems != null)
                {
                    Person person = (Person)e.NewItems[0];
                    person.PropertyChanged += onPropertyChanged;
                }
     
                //Fonction Suppression
                if (e.OldItems != null)
                {
                    Person person = (Person)e.OldItems[0];
                    person.PropertyChanged -= onPropertyChanged;
                    DeleteItems(e.OldItems.Cast<object>().ToList());
                }
            }
    Je vous joins le code de ce projet ci besoin.
    https://github.com/Zeratec/Training_WPFMVVM

    Cet exercice m'a permis de bien cerner l'implémentation des fonctions de bases d'ajout/modif/supp sans passer par un formulaire.

    Je suis à l'écoute de vos remarques afin d'améliorer ce code.

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

Discussions similaires

  1. [MySQL] Modification et ajout de donnée depuis un formulaire
    Par masterix59 dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 18/01/2010, 15h13
  2. [présentation données bdd] formulaire ajout, supp, mod
    Par coye dans le forum Windows Forms
    Réponses: 0
    Dernier message: 12/02/2009, 09h16
  3. Formulaire d'ajouter/ suppression/ modification
    Par supertoms dans le forum VBA Access
    Réponses: 1
    Dernier message: 03/06/2008, 15h16
  4. impossible ajout/supp composants Win sans le cd
    Par Ochman dans le forum Windows XP
    Réponses: 4
    Dernier message: 27/06/2007, 10h58
  5. dbgrid ou datagrid ajouter et modif d'enregistrement
    Par thierry007 dans le forum VB 6 et antérieur
    Réponses: 15
    Dernier message: 21/09/2006, 07h55

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