none
Données XML : synchroniser la navigation RRS feed

  • Discussion générale

  • Bonjour tout le monde,

    Il y a quelque temps de cela j'ai développé une application, basée sur un DataSet créé à partir d'une table SQL Server, mais il s'agissait simplement d'une commodité adaptée à un poil dans la main : un glissé de souris de l'explorateur de serveurs vers le formulaire permet d'obtenir simultanément la source de données et le navigateur de données liées, le tout synchronisé automatiquement.

    En fait, l'application sauvegarde ses données sous forme de fichier XML, et les retrouve ensuite depuis le fichier XML.

    Aussi, à présent, je retouche l'application pour en retirer la référence à SQL Server, ce qui sera quand même plus logique quand je voudrai faire un déploiement.

    A moins que j'aie raté quelque chose (et ça m'intéresserait grandement), cela m'oblige à écrire moi-même la synchronisation entre la source de données et le navigateur de données. Aussi, j'aimerais m'assurer que ce que j'ai fait est suffisamment orthodoxe, que je ne m'en suis pas sorti par une pirouette qui pourrait me jouer des tours.

    Je ne vois pas trop comment faire autrement que fournir du code, pardon pour la longueur. En première saisie j'ai utilisé un formulaire de saisie de code, et puis je n'y ai pas vu de bouton de validation. Je vais voir en modification si j'ai plus de chance (est-ce que ça n'est pas censé fonctionner en 800x600 ? Là en 1024x600, pas de bouton).

    Sur le formulaire, j'ai tabRepetBindingNavigator, et bindingSource1, donc respectivement le navigateur de données liées et la source de données.

    Nous avons deux classes, Tache et XMLTache, qui définissent respectivement le contenu et le traitement, selon ce modèle :
    http://www.codeproject.com/KB/database/XMLData/XMLData_src.zip

    Ce que ce modèle ne fournit pas, c'est la synchronisation du navigateur de données.

    Au chargement du formulaire :

                this.ds = new DataSet();
                this.ds.ReadXml("LaSonnaille.xml");
                ds.Tables[0].TableName = "tabRepet";
                IList List = XMLData.DAL.XMLTache.SelectAll();
                //this.tabRepetDataGridView.DataSource = List;

                //this.tabRepetBindingNavigator.BindingSource = (System.Windows.Forms.BindingSource) List;
                //for (int n = 0; n < dataSet1.Tables[0].Columns.Count; n++)
                    //MessageBox.Show(dataSet1.Tables[0].Columns[n].ColumnName);
                //MessageBox.Show(dataSet1.Tables[0].Columns.Count.ToString());
                //this.ds.Tables[0].Columns.Add("booActive", typeof(Boolean), "true");

                //MessageBox.Show(dataSet1.Tables[0].Columns.Count.ToString());
               
                this.tabRepetBindingNavigator.BindingSource = new BindingSource();
                this.tabRepetBindingNavigator.BindingSource.DataSource = ds;
                this.tabRepetBindingNavigator.BindingSource.DataMember = "tabRepet";
    //            this.tabRepetBindingNavigator.BindingSource = bindingSource1;
                this.bindingSource1.DataSource = ds;
                this.bindingSource1.DataMember = "tabRepet";
                this.repDateDateTimePicker.DataBindings.Add("Value", this.tabRepetBindingNavigator.BindingSource, "repDate");
                repIntituleTextBox.DataBindings.Add("Text", this.tabRepetBindingNavigator.BindingSource, "repIntitule");
                this.checkBox1.DataBindings.Add("Checked", this.tabRepetBindingNavigator.BindingSource, "booActive");
                repIntervalleTextBox.DataBindings.Add("Text", this.tabRepetBindingNavigator.BindingSource, "repIntervalle");
                this.tabRepetDataGridView.DataSource = ds.Tables[0];
                //this.tabRepetDataGridView.DataBindings.Add("CurrencyManager.Position", this.tabRepetBindingNavigator.BindingSource, "currentrow");
                //MessageBox.Show(tabRepetDataGridView.Columns.Count.ToString());


    Dans la fonction ChargeListe, exécutée à l'initialisation du formulaire :

                    ds = new DataSet();
                    //ds.Load(reader, LoadOption.Upsert, ds.Tables["tabRepet"]);
                    ds.Reset();
                    ds.ReadXml("LaSonnaille.xml");

                    //ds.Tables[0].Columns.Add("DateCible", typeof(DateTime));
                    DataTable dt = new DataTable("tabRepet");
                    try
                    {
                        dt.Columns.Add(new DataColumn("repIntitule", typeof(String)));
                        dt.Columns.Add(new DataColumn("repDate", typeof(DateTime)));
                        dt.Columns.Add(new DataColumn("repIntervalle", typeof(Int32)));
                        dt.Columns.Add(new DataColumn("DateCible", typeof(long))); //, Convert.ToInt32(repDate) + repIntervalle));


                        DataViewManager dvm = new DataViewManager(ds);

                        dvm.DataViewSettings["tabRepet"].Sort = "DateCible";


                        dt.DefaultView.Sort = "DateCible";
                    }

    Je vous fais grâce du calcul de la date de fin, pas vraiment dans le sujet.

    Et ... le meilleur pour la fin :

            private void bindingNavigatorMoveNextItem_Click(object sender, EventArgs e)
            {
                bindingSource1.Position = bindingSource1.Position + 1;
            }

            private void bindingSource1_PositionChanged(object sender, EventArgs e)
            {
                tabRepetDataGridView.ClearSelection();
                if (tabRepetDataGridView.Rows.Count > 0)
                    tabRepetDataGridView.Rows[bindingSource1.Position].Cells[0].Selected = true;
            }

            private void bindingNavigatorMovePreviousItem_Click(object sender, EventArgs e)
            {
                bindingSource1.Position = bindingSource1.Position - 1;
            }

            private void tabRepetDataGridView_RowEnter(object sender, DataGridViewCellEventArgs e)
            {
                //MessageBox.Show(e.RowIndex.ToString());
                bindingSource1.Position = e.RowIndex;
                tabRepetBindingNavigator.BindingSource.Position = bindingSource1.Position;
            }


    Donc, vous voyez que je gère la position de l'enregistrement sélectionné dans le code du bouton "Précédent", dans celui du bouton "Suivant", pour ce qui est de sélectionner un enregistrement à l'aide des boutons, et dans l'événement RowEnter du DataGridView, pour ce qui est de sélectionner un enregistrement en cliquant dessus.

    ça marche, je voudrais m'assurer que je n'ai pas utilisé une logique trop capillotractée.

     

    lundi 9 mai 2011 14:53

Toutes les réponses

  • Bonjour,

    Pouvez-vous nous expliquer en plus des détails quelle est le rôle du fichier XML et aussi et quelle est le rôle des votre base des données dans cet application ? Je ne suis pas sûr d’avoir bien compris ce que vous voulez faire. Merci !

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    vendredi 13 mai 2011 12:46
  • Bonjour,

    Le fichier XML contient les données, c'est aussi simple que cela. On les lit par ds.ReadXml(), on enregistre les modifications par ds.WriteXml()

    C'est pour définir le DataSet qu'il y a un peu plus de boulot, alors que pour des données lues dans une base de données, concrètement on définit les données en les glissant de l'explorateur de serveurs vers l'éditeur de Dataset. Alors au début j'avais fait comme ça, j'ai créé une table dans SQL Server, les données ont été lues de là, sauvegardées par ds.WriteXml, puis à partir de là la table SQL Server pouvait rester vide, peu importe, puisque les données sont lues dans le fichier XML.

    Maintenant, j'ai décidé de faire quelque chose d'un peu plus orthodoxe : puisque je n'utilise pas le contenu de la table SQL Server, autant que l'application ne s'y réfère pas. Alors j'ai défini explicitement le contenu du fichier XML.

    Si ça peut se faire automatiquement comme à partir d'une base de données ça m'intéresse, mais il me semble bien que non, alors j'ai écrit une ligne de code pour chaque champ.

    Je ne sais pas si c'est plus clair, car j'ai l'impression d'avoir à peu près redit la même chose ?
    vendredi 13 mai 2011 14:35
  • Bonjour,

    Merci pour les explications. En cette situation je crois que votre méthode n’est pas trop capillotractée. Ma seule question est sur le chargement du formulaire : l’objet bindingSource1 est initialisé après l’initialisation de this.tabRepetBindingNavigator.BindingSource, mais les deux BindingSources contiennent les mêmes infos. Et puis vous utilisez l’objet bindingSource1 pour gérer la position : tout d’abord dans bindingSource1 et puis vous avez cette ligne tabRepetBindingNavigator.BindingSource.Position = bindingSource1.Position;

     

    Je crois qu’il faut initialiser l’objet bindingSource1 et puis utiliser this.tabRepetBindingNavigator.BindingSource = bindingSource1 et la ligne tabRepetBindingNavigator.BindingSource.Position = bindingSource1.Position; ne devrait pas être nécessaire.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    lundi 16 mai 2011 07:14
  • Me voilà donc rassuré sur mon approche de la question, cela étant il va effectivement falloir que je regarde de près cette histoire de doublon. J'ai l'impression que ça ne va pas être avant la fin de la semaine -où j'ai déjà une histoire de Dataset récalcitrant à examiner dans un autre projet, probablement due au même type d'erreur. Merci pour les réponses.
    mercredi 18 mai 2011 08:39
  • Bonjour,

    De rien. Merci d’avance pour tenir la communauté informée sur la suite de vos démarches.

    Cordialement,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    jeudi 19 mai 2011 07:46
  • Alors je ne suis pas sûr d'avoir utilisé la structure de programme la plus élégante, mais la raison d'être de BindingSource1 est de pouvoir utiliser son événement PositionChanged, de façon que le BindingNavigator soit synchronisé avec le DataGridView (ce qui, au passage, constitue le titre de ce fil).

    Effectivement lorsque j'utilise les boutons de défilement du BindingNavigator, la ligne dont le numéro s'affiche est bien sélectionnée, ou en tout cas sa première cellule, grâce à l'instruction

    tabRepetDataGridView.Rows[bindingSource1.Position].Cells[0].Selected = true;

    Est-ce que je peux créer des événements directement sur la BindingSource du BindingNavigator ?

    A propos de synchronisation, pendant qu'on y est, peut-être que cosmétiquement on peut l'améliorer encore un peu : la ligne voulue est bien sélectionnée, ce qui se matérialise par une couleur de fond plus foncée sur la première cellule, mais le petit triangle supposé figurer la ligne sélectionnée, à gauche, reste devant la première ligne.
    mardi 24 mai 2011 11:53
  • Bonjour,

    Non, vous ne pouvez pas définir des évènements directement sur la BindingSource du BindingNavigator. Les évènements sont définis sur l’interface, donc pour votre BindingNavigator, mais vous avez accès à son BindingSource et vous pouvez faire la même action par :

    tabRepetDataGridView.Rows[tabRepetBindingNavigator.BindingSource.Position].Cells[0].Selected = true;

    Pour votre deuxième problème je crois qu’il faut aussi sélectionner la ligne de votre DataGridView :

    tabRepetDataGridView.Rows[tabRepetBindingNavigator.BindingSource.Position].Selected = true;

    Bonne journée,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    jeudi 26 mai 2011 11:58
  • Bonjour,

    Non, vous ne pouvez pas définir des évènements directement sur la BindingSource du BindingNavigator. Les évènements sont définis sur l’interface, donc pour votre BindingNavigator, mais vous avez accès à son BindingSource et vous pouvez faire la même action par :

    tabRepetDataGridView.Rows[tabRepetBindingNavigator.BindingSource.Position].Cells[0].Selected = true;

    D'accord, mais la question qui se pose serait surtout : dans quel événement placer cette instruction ?

     

    jeudi 26 mai 2011 12:37
  • Bonjour,

    Il y a deux possibilités :

    1)   vous le mettez dans toutes les fonctions où vous modifiez la position dans votre BindingNavigator

    2)    vous créez une fonction qui est appelée dans toutes les fonctions où vous modifiez la position dans votre BindingNavigator :

    private void DGChangePosition()
            {
                tabRepetDataGridView.ClearSelection();
                if (tabRepetDataGridView.Rows.Count > 0)

    {

       tabRepetDataGridView.Rows[tabRepetBindingNavigator.BindingSource.Position]. Selected = true;
                   
    tabRepetDataGridView.Rows[tabRepetBindingNavigator.BindingSource.Position].Cells[0].Selected = true;

    }
            }

    et puis l’appel sera simplement :

    DGChangePosition()

     

    Je vous recommande la deuxième solution.

    Bonne journée,

    Cipri


    Suivez MSDN sur Twitter   Suivez MSDN sur Facebook


    Ciprian DUDUIALA, MSFT  
    •Nous vous prions de considérer que dans le cadre de ce forum on n’offre pas de support technique et aucune garantie de la part de Microsoft ne peut être offerte.

    jeudi 26 mai 2011 12:45
  • Ah oui ça c'est pour la deuxième question :)

    Il va falloir que j'essaie, probablement ce soir.

    Autant pour les boutons du BindingNavigator c'est assez évident, autant c'est pour la sélection d'une ligne par clic sur la grille que je ne me représente pas bien ...

     

    jeudi 26 mai 2011 13:07
  • Alors comme  prévu j'ai mis ça à la fin du InitializeComponent :

    this.tabRepetBindingNavigator.BindingSource.PositionChanged += new System.EventHandler(this.DGChangePosition);

    mais sur cette instruction j'ai une NullReferenceException :

    La référence d'objet n'est pas définie une instance d'un objet.

    J'ai pourtant écrit DGChangePosition avec la bonne signature :

    private void DGChangePosition(object sender, EventArgs e)

    J'ai dû oublier une initialisation quelque part, mais je ne la vois pas en pistant une autre procédure événementielle, pourtant située dans le même module.

    Il est où, le couac ?

    (à part ça j'en ai bavé pour que ce message soit lisible : en faisant un copier/coller avec juste le texte ça simplifie le code de mise en forme, mais j'ai quand même cinq span incorporés l'un dans l'autre sur tout le message, avec chacun pour attribut size=xsmall, donc au bout il fallait une loupe)



    dimanche 29 mai 2011 17:00