Partage
  • Partager sur Facebook
  • Partager sur Twitter

BindingSource et DataSource sous-jacente

Sujet résolu
    15 août 2011 à 1:15:46

    Bonsoir,

    mon entreprise m'a demandé de créer un petit outil de gestion de véhicules. Le but est simple, construire une base de données très simple qui contiendrait pour chaque voiture :
    • Le numéro d'immatriculation
    • La date d'acquisition du véhicule
    • La nom du conducteur principal
    • Le numéro de la carte Total associée au véhicule pour les pleins d'essence

    Pour cela j'ai utilisé une simple association DataGridView et BindingSource pour la gestion des données. Ce qui donne la GUI suivante :
    Image utilisateur

    Voilà le code qui permet de créer la table de données :
    private DataTable dataTableVehicules;
    private DataColumn dataColumnImmatriculation;
    private DataColumn dataColumnDateAcquisition;
    private DataColumn dataColumnNomConducteur;
    private DataColumn dataColumnCarteTotalAssociee;
    private List<Vehicule> vehicules;
    private XmlSerializer serializer;
    
    public MainForm()
    {
       InitializeComponent();
    
       dataTableVehicules = new DataTable("DataTableVehicules");
    
       dataColumnImmatriculation = dataTableVehicules.Columns.Add("Immatriculation");
       dataColumnImmatriculation.Unique = true;
       dataColumnDateAcquisition = dataTableVehicules.Columns.Add("Date d'acquisition");
       dataColumnNomConducteur = dataTableVehicules.Columns.Add("Nom du conducteur");
       dataColumnCarteTotalAssociee = dataTableVehicules.Columns.Add("Carte Total associée");
    
       vehicules = new List<Vehicule>();
    
       serializer = new XmlSerializer(vehicules.GetType());
    }
    

    Ce code-ci fonctionne parfaitement à l'exécution. Le code qui permet de peupler initialement la table semble fonctionner aussi :
    private void MainForm_Load(object sender, EventArgs e)
            {
                try
                {
                    FileStream fileStream = File.OpenRead("vehicules.xml");
    
                    vehicules = (List<Vehicule>)serializer.Deserialize(fileStream);
    
                    fileStream.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    foreach (Vehicule vehicule in vehicules)
                    {
                        DataRow newRow = dataTableVehicules.NewRow();
                        newRow[dataColumnImmatriculation] = vehicule.immatriculation;
                        newRow[dataColumnDateAcquisition] = vehicule.dateAcquisition;
                        newRow[dataColumnNomConducteur] = vehicule.nomConducteur;
                        newRow[dataColumnCarteTotalAssociee] = vehicule.carteTotalAssociee;
                        dataTableVehicules.Rows.Add(newRow);
                    }
    
                    foreach (DataColumn column in dataTableVehicules.Columns)
                    {
                        dataGridViewVehicules.Columns.Add(column.ColumnName, column.ColumnName);
                    }
    
                    bindingSourceVehicules.DataSource = dataTableVehicules;
                }
            }
    

    C'est à ce moment que l'utilisateur peut rajouter, supprimer ou modifier les données. J'enregistre les modifications de la manière suivante à la fermeture du formulaire :
    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
            {
                try
                {
                    FileStream fileStream = File.OpenWrite("vehicules.xml");
    
                    vehicules.Clear();
                    foreach (DataRow row in ((DataTable)bindingSourceVehicules.DataSource).Rows)
                    {
                        Vehicule vehicule = new Vehicule();
                        vehicule.immatriculation = (string)row[dataColumnImmatriculation];
                        vehicule.dateAcquisition = (string)row[dataColumnDateAcquisition];
                        vehicule.nomConducteur = (string)row[dataColumnNomConducteur];
                        vehicule.carteTotalAssociee = (string)row[dataColumnCarteTotalAssociee];
                        vehicules.Add(vehicule);
                    }
    
                    serializer.Serialize(fileStream, vehicules);
    
                    fileStream.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
    

    Ce code, qui ne cause pas d'erreur à la compilation, fait apparaître certains bugs à l'exécution. Premièrement, supposons que la table de données soit vide et que je rajoute une ligne de donnée. Un debug dans le code de la fonction de fermeture du formulaire montre que la dataTable contient effectivement une ligne de donnée, mais celle-ci est constituée uniquement de données vides.
    Deuxième, si je rajoute deux lignes de données, la validation de la deuxième ligne déclenche l'erreur suivante :
    Image utilisateur
    J'ai effectué pas mal de debug pour tenter de trouver l'origine du problème, je me suis inspiré de codes sources existants dans la MSDN Library, mais je me trouve à présent à court de solutions :euh:

    Merci
    • Partager sur Facebook
    • Partager sur Twitter
      15 août 2011 à 2:43:10

      Tu te compliques méchamment la vie en voulant utiliser une DataTable comme DataSource.
      Tu peux très bien utiliser directement ta liste de Vehicules comme DataSource de ta BindingSource :)

      Donc:

      private List<Vehicule> _vehicules;
      private XmlSerializer _serializer;
      
      public MainForm()
      {
         InitializeComponent();
      
         _serializer = new XmlSerializer(typeof(List<Vehicule>));
      }
      
      private void MainForm_Load(object sender, EventArgs e)
      {
          try
          {
              FileStream fileStream = File.OpenRead("vehicules.xml");
              _vehicules = (List<Vehicule>)_serializer.Deserialize(fileStream);
          }
          catch(Exception ex)
          {
              MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
             _vehicules = new List<Vehicule>();
          }
          finally
          {
              fileStream.Close();
              this.bindingSourceVehicules.DataSource = _vehicules;
          }
      }
      
      private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
      {
          try
          {
              FileStream fileStream = File.OpenWrite("vehicules.xml");
              _serializer.Serialize(fileStream, _vehicules);
          }
          catch(Exception ex)
          {
              MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
          }
          finally
          {
              fileStream.Close();
          }
      }
      


      (Observe au passage la bonne utilisation du bloc finally.)

      Les colonnes de la DataGridView peuvent être définies facilement en mode Design (en particulier pour leur donner un header plus sympa). ^^
      • Partager sur Facebook
      • Partager sur Twitter
        15 août 2011 à 9:35:57

        Au sujet du bloc finally, une chose me surprend, l'objet FileStream est déclaré dans le bloc try, donc, sauf erreur de ma part, sa portée s'arrête au bloc try et il n'existe déjà plus dans le bloc finally, non ?

        J'avoue que c'est la première fois que je fais de l'accès de l'accès aux données en .NET et je voyais ça plus efficace de me lancer dans une programmation avec Dataset et compagnie ! Le fait de mettre directement la liste comme DataSource de mon BindingSource m'avait effleuré l'esprit, mais je ne pensais pas que ça fonctionnerait ^^
        Malheureusement, il reste toujours un bug que je ne comprends pas :euh:
        Voici une capture d'écran des données que j'ai rempli et qui devraient donc normalement être serializées :
        Image utilisateur
        Sauf qu'un debug au niveau de la fonction de fermeture du formulaire montre que dans la BindingSource remplit des données vide :
        Image utilisateur
        Aurais-je sauté une étape ?
        • Partager sur Facebook
        • Partager sur Twitter
          15 août 2011 à 12:06:08

          Citation : DIPMan

          Au sujet du bloc finally, une chose me surprend, l'objet FileStream est déclaré dans le bloc try, donc, sauf erreur de ma part, sa portée s'arrête au bloc try et il n'existe déjà plus dans le bloc finally, non ?


          Au temps pour moi, ça m'apprendra à jouer au donneur de leçon. >_< Le FileStream doit effectivement être déclaré auparavant. Je voulais surtout mettre en évidence le fileStream.Close() dans le bloc finally et pas dans le bloc try (de manière à ce que le stream soit fermé même en cas d'erreur).

          Citation : DIPMan

          J'avoue que c'est la première fois que je fais de l'accès de l'accès aux données en .NET et je voyais ça plus efficace de me lancer dans une programmation avec Dataset et compagnie ! Le fait de mettre directement la liste comme DataSource de mon BindingSource m'avait effleuré l'esprit, mais je ne pensais pas que ça fonctionnerait ^^


          Les DataSets (et DataTables) c'est vieux, c'est moche, et c'est obsolète. :ange:

          Citation : DIPMan


          Sauf qu'un debug au niveau de la fonction de fermeture du formulaire montre que dans la BindingSource remplit des données vide :
          Image utilisateur
          Aurais-je sauté une étape ?



          L'assignation de la BindingSource est faite au niveau de la fermeture du formulaire ? :o

          Sinon d'après ce que je peux voir, tes objets Vehicules possèdent des attributs carteTotalAssociee, dateAcquisition etc et pas des propriétés CarteTotalAssociee, DateAcquisition etc. De manière générale quand tu lies des objets à des contrôles ce sont leurs propriétés qui sont utilisées par défaut. J'ai fait l'essai de mon côté avec des propriétés et tout a l'air en ordre. Au fait, ta BindingSource bindingSourceVehicules est-elle bien de type "Object" ?
          • Partager sur Facebook
          • Partager sur Twitter
            15 août 2011 à 15:15:13

            Citation : Orwell

            L'assignation de la BindingSource est faite au niveau de la fermeture du formulaire ? :o


            Nan nan ^^ en fait sur le screenshot, les infos de debug empêchent de voir le code source en-dessous, la ligne de code "bindingSourceVehicules.DataSource = vehicules" est dans la fonction void MainForm_Load(...) et le code qui suit c'est la fonction void MainForm_FormClosing(...) ;)

            Je vais essayer de modifier la classe Vehicule en y ajoutant des accesseurs pour voir si effectivement le problème vient de là ;)

            EDIT : j'ai modifié la classe Vehicule en rajoutant les accesseurs. Je leur ai donnés le même nom que les noms des colonnes pour s'assurer que .NET fasse bien le lien entre les colonnes et les accesseurs. Mais toujours le même bug :
            Image utilisateur

            Citation : Orwell

            Au fait, ta BindingSource bindingSourceVehicules est-elle bien de type "Object" ?


            J'ai du mal à saisir ta question ! Là à froid comme ça je dirais que ma BindingSource bindingSourceVehicules est de type "BindingSource" ^^ et a fortiori par héritage elle est de type "Object" de par la conception même du .NET Framework !
            • Partager sur Facebook
            • Partager sur Twitter
              15 août 2011 à 15:45:01

              Citation : DIPMan

              Citation : Orwell

              Au fait, ta BindingSource bindingSourceVehicules est-elle bien de type "Object" ?


              J'ai du mal à saisir ta question ! Là à froid comme ça je dirais que ma BindingSource bindingSourceVehicules est de type "BindingSource" ^^ et a fortiori par héritage elle est de type "Object" de par la conception même du .NET Framework !


              Je me doutais que ma question n'était pas très claire. Quand tu crées une nouvelle Data Source, tu as le choix entre différentes types de sources selon la provenance des données:

              Image utilisateur

              Dans ton cas, il faut choisir le type "Object", ce qui te permettra de choisir ta classe GestionVehicules.Vehicule comme "modèle" de données.

              Citation : DIPMan

              Je leur ai donnés le même nom que les noms des colonnes pour s'assurer que .NET fasse bien le lien entre les colonnes et les accesseurs.


              Ce qui va faire le lien entre une colonne et la propriété de Vehicule qu'elle exploite, ce n'est pas le nom de la colonne mais sa propriété DataPropertyName (déjà assignée par défaut si tu as créé ta BindingSource à partir de ta classe Vehicule puis que tu l'as spécifiée comme source de ta DataGridView):

              Image utilisateur
              • Partager sur Facebook
              • Partager sur Twitter
                15 août 2011 à 16:18:51

                Ah ba oui, en me mettant sous le nez le screenshot de l'assistant de VS 2010, d'un coup ta question prend tout son sens :p
                D'ailleurs ça me fait comprendre pourquoi je ne comprenais pas ta question : je ne suis pas passé par les designers de VS 2010 pour paramétrer la DataGridView et la BindingSource. Je les ai ajoutés à la main dans mon formulaire et en réglant les propriétés je suis passé à côté du paramètre DataPropertyName qu'en fait je ne connaissais pas !
                Ainsi finalement, j'ai réglé ce paramètre pour chaque colonne et... ça marche :)

                Merci bien ^^
                • Partager sur Facebook
                • Partager sur Twitter

                BindingSource et DataSource sous-jacente

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown