Probleme mise a jour display de controle sur Form [Résolu]

Signaler
-
 mickbristol78 -
Hello, en tant que debutant je me lance a ecrire un programme.
Ce programme (qui n'est pas fini) est une sorte de calendrier, mais il affichera les depenses, et peut etre eventuellement aussi des rendez vous comme un calendrier normal.
J'utilise une photo qui, en backgroundimage du Form principal, montre tous les jours de l'année ainsi que les mois.
Chaque depense, par exemple "Mortgage" est representé par un label, legerement modifiée pour obtenir un rectangle de couleur de 10pixel sur 10, sans text. Chaque label ajoute un control au Form afin de generer des evenements comme MouseEnter (qui a pour but d'afficher les details de la depense en question) ou encore MouseClick (qui permet d'ouvrir une autre Form pour pouvoir modifier la depense concernée).
Toutes les données sont stockées dans un fichier xml externe.

Viens le probleme mais avant j'explique encore un peu ma demarche;
Si je veux afficher l'année 2012 et ses depenses, alors je retire tous les controls de 2013 creé auparavant en faisant
        private void RemoveOldRectangles()
        {
            while (ControlsToRemove != 0)
            {
                this.Controls.Remove(this.Controls[IndexControlsToRemove]);
                ControlsToRemove--;
            }
        }

Ensuite je change l'image de fond par une autre correspondant a 2012 puis je relance les methodes de recherche et d'affichage des depenses 2012 trouvées dans le xml.
Tout marche correctement.

Maintenant, le probleme est quand je veux modifier une depense, donc quand je click sur un rectangle correspondant. J'ouvre une autre Form en passant les valeurs actuelles dans des textbox etc.. (au passage je ne suis pas sur d'utiliser la meilleur facon pour passer les valeurs, En fait losrque ma sourie entre dans la depense et donc declenche le MouseEnter, j'en profite pour copier les valeurs dans des variables globales, que je rappellerai depuis mon evenement MouseClick, et passerai en parametre dans une methode de la Formfille).

Bref je parviens a modifier mes valeurs et a sauvegarder mon xml de retour dans ma form principal, du coup je relance le processus de trouver dans mon xml les depenses de 2013, et relance le processus de creer les labels (ainsi que les controls) tout comme le programme fait a sa premiere excecution. Sauf que la, la depense modifer (changée de date par example) ne bouge pas et reste a la place ou il etait avant la modification ... !!

J'ai pourtant bien le xml sauvé avant la relecture.. et en debug je vois bien qu'il lit la bonne nouvelle date, mais rien ne se passe juste au niveau du display.

le bout de code suivant est ma methode dans la Form proncipale pour trouver les depenses correspondantes a l'année et a afficher les labels et controls correspondants
private void ProceedDisplay()
        {
            XmlDocument myDoc = new XmlDocument();
            myDoc.Load(dataFile);

            ControlsToRemove = 0;
            // Reset the table containing the rectangle positions
            ResetYearTablePositions();
            // Get the type of what to display; "Bills" or "Garantees"
            string xPathExp = comboBoxPrimary.Text;
            // Select the Node pointed just above
            XmlNode xNode = myDoc.SelectSingleNode("//Datas/" + xPathExp);
            // read the Year displayed in the label
            string ActiveYear = labelYear.Text;
            // search for all Node containing an argument "Year" which is equal to the label.text read just above
            xPathExp = "//*[@BillYear='" + ActiveYear + "']";
            // get a list of all the nodes which match the research just above
            XmlNodeList xNodes = myDoc.SelectNodes(xPathExp);

            int OriginalControls = this.Controls.Count;
            IndexControlsToRemove = OriginalControls;
            int i;
            for (i = 0; i < xNodes.Count; i++)
            {
                Bill CurrentBill = new Bill();
                CurrentBill.ID = Convert.ToInt32(xNodes[i].Attributes[0].InnerText);
                CurrentBill.Day = xNodes[i].Attributes[1].InnerText;
                CurrentBill.Month = xNodes[i].Attributes[2].InnerText;
                CurrentBill.Year = Convert.ToInt32(xNodes[i].Attributes[3].InnerText);
                CurrentBill.Amount = Convert.ToInt32(xNodes[i].Attributes[4].InnerText);
                CurrentBill.Notes = xNodes[i].Attributes[7].InnerText;
                CurrentBill.Color = xNodes[i].ParentNode.PreviousSibling.InnerText;
                int Position = AttributePosition(CurrentBill.Day, CurrentBill.Month, CurrentBill.Year);
                DrawRectangle(Convert.ToInt32(CurrentBill.Day), Convert.ToInt32(CurrentBill.Month), CurrentBill.ID, Position, CurrentBill.Color);
            }
            ControlsToRemove = this.Controls.Count - OriginalControls;
        }


la methode DrawRectangle est la suivante
        public void DrawRectangle(int Day, int Month, int ID, int Position, string ParaColor)
        {
            Month = RectX(Month);
            Month = Month + (13 * (Position));
            Day = RectY(Day);
            Label lbl = new Label();
            lbl.Name = ID.ToString();
            lbl.Top = Day;
            lbl.Left = Month;
            if (ParaColor "Black") lbl.BackColor Color.Black;
            else if (ParaColor "Green") lbl.BackColor Color.Green;
            else if (ParaColor "Red") lbl.BackColor Color.Red;
            else if (ParaColor "Yellow") lbl.BackColor Color.Yellow;
            lbl.Size = new System.Drawing.Size(10, 10);
            lbl.MouseEnter += lbl_MouseEnter;
            lbl.Click += lbl_Click;
            lbl.MouseLeave += lbl_MouseLeave;
            this.Controls.Add(lbl);
        }


la methode de la form mere, pour metre a jour les données apres avoir été modifier dans la form fille est la suivante
        public void UpdateValuesFromEditPayment(int DayUpdated, int MonthUpdated, int YearUpdated, int AmountUpdated, string NotesUpdated, int IDUpdated)
        {
            XmlDocument myDoc = new XmlDocument();
            myDoc.Load(dataFile);

            string xPathExp = "//*[@ID=" + IDUpdated.ToString() + "]";
            XmlNode xNode = myDoc.SelectSingleNode(xPathExp);

            if (DayUpdated.ToString().Length < 2) xNode.Attributes[1].InnerText = "0" + DayUpdated.ToString();
            else xNode.Attributes[1].InnerText = DayUpdated.ToString();

            if (MonthUpdated.ToString().Length < 2) xNode.Attributes[2].InnerText = "0" + MonthUpdated.ToString();
            else xNode.Attributes[2].InnerText = MonthUpdated.ToString();

            xNode.Attributes[3].InnerText = YearUpdated.ToString();
            xNode.Attributes[4].InnerText = AmountUpdated.ToString();
            xNode.Attributes[7].InnerText = NotesUpdated;

            myDoc.Save(dataFile);
            myDoc.Load(dataFile);
            RemoveOldRectangles();
            ProceedDisplay();
        }


et la methode de la Form mere MouseEnter, lorsque la sourie Entre une depense affichée
        void lbl_MouseEnter(object sender, EventArgs e)
        {
            XmlDocument myDoc = new XmlDocument();
            myDoc.Load(dataFile);

         //   label1.Text = "mouse has entered label number " + ((Label)sender).Name;
            string xPathExp = ((Label)sender).Name;
            TempID = Convert.ToInt32(xPathExp);
            xPathExp = "//*[@ID= " + xPathExp +"]";
            XmlNode xNode = myDoc.SelectSingleNode(xPathExp);

            Bill CurrentBill = new Bill();
            CurrentBill.Day = xNode.Attributes[1].InnerText;
            CurrentBill.Month = xNode.Attributes[2].InnerText;
            CurrentBill.Year = Convert.ToInt32(xNode.Attributes[3].InnerText);
            CurrentBill.Amount = Convert.ToInt32(xNode.Attributes[4].InnerText);
            CurrentBill.Notes = xNode.Attributes[7].InnerText;

            TempDay = Convert.ToInt32(CurrentBill.Day);
            TempMonth = Convert.ToInt32(CurrentBill.Month);
            TempYear = Convert.ToInt32(CurrentBill.Year);
            TempNotes = CurrentBill.Notes;
            TempAmount = CurrentBill.Amount;

            labelAmount.Text = CurrentBill.Amount.ToString();
            labelNotes.Text = CurrentBill.Notes;
            labelPayee.Text = xNode.ParentNode.ParentNode.FirstChild.InnerText;
            labelRecurrence.Text = xNode.ParentNode.ParentNode.FirstChild.NextSibling.InnerText;
            labelIn_Out.Text = xNode.Attributes[6].InnerText;

            Cursor = Cursors.Hand;
        }


voila, j'espere avoir été assez clair, si quelqu'un a une idées ? merci beaucoup

11 réponses


ok j'arrive a qq chose, mais je ne comprends pas trop comment ca marche, j'ai pris un example ici

il me fallait
        EditPayment editPaymentForm;

dans les Globales de ma Form1


puis
        void lbl_Click(object sender, EventArgs e)
        {
            editPaymentForm = new EditPayment(this);
            editPaymentForm.Show();
            editPaymentForm.EditDisplay(TempDay, TempMonth, TempYear, TempAmount, TempNotes, TempID);
        }

pour appeller la form fille


puis
        private Form1 frmParent;

en globale de ma form fille

pour le constructeur de la form fille
        public EditPayment(Form1 frmParent)
        {
            InitializeComponent();
            this.frmParent = frmParent;
        }



et enfin pour fermer la form fille et revenir a la form mere
        private void buttonSaveAndClose_Click(object sender, EventArgs e)
        {
            Amount = Convert.ToInt32(textBoxEditAmount.Text);
            Notes = textBoxEditPaymentNote.Text;
            frmParent.UpdateValuesFromEditPayment(Day, Month, Year, Amount, Notes, ID);
            this.Close();
        }



je ne comprends pas trop l'histoire pour passer la Form1 en parametre, mais bon..

merci encore pour ton aide
Messages postés
15134
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
23 novembre 2020
462
Bonjour
Chaque label ajoute un control au Form afin de generer des evenements comme MouseEnter
un label est déjà un controle qui peut générer des évenements, je ne comprends pas ta phrase du coup.


au passage je ne suis pas sur d'utiliser la meilleur facon pour passer les valeurs, En fait losrque ma sourie entre dans la depense et donc declenche le MouseEnter, j'en profite pour copier les valeurs dans des variables globales, que je rappellerai depuis mon evenement MouseClick, et passerai en parametre dans une methode de la Formfille

Il n'est pas conseillé en C# d'utiliser des variables globales (je ne sais plus trop pourquoi). Ce serait peut être plus pratique de charger tout ton xml dans un contenant de donnée (list<T> par exemple) et ensuite de gérer les données via LinQ, mais c'est à toi de voir.

Des exemples ou

De cette façon, peut être pourrais tu gerer une seule dépenses à la fois au lieu de tout effacer et tout redessiner.

Si tu fais ça est ce que ça te mets page vierge?
            myDoc.Save(dataFile);
            myDoc.Load(dataFile);
            RemoveOldRectangles();
            //ProceedDisplay();


Whismeril

Salut,

Chaque label ajoute un control au Form afin de generer des evenements comme MouseEnter


oui je veux dire que des que j'ai la commande
            this.Controls.Add(lbl);

alors mon control est ajouté, je ne fais rien d'autre.

Il n'est pas conseillé en C# d'utiliser des variables globales (je ne sais plus trop pourquoi)

Je pense que les globales ne sont pas trop aimées car d'une elles prennent de la place (surtout si elle sont copiées en parametre par valeur a chaque fois) et aussi parce que je pense que le but de la POO est de faire des Class reutilisable, et si j'utilise des Globales je pourrai pas trop reutiliser mes Class dans un autre programme. Enfin c'est ce dont je pense mais je peux me tromper.

Ce serait peut être plus pratique de charger tout ton xml dans un contenant de donnée (list<T> par exemple) et ensuite de gérer les données via LinQ, mais c'est à toi de voir.

Je pensais aussi a charger toutes mes données du xml en memoire et travailler avec la memoire plutot que d'acceder a un fichier externe, mais je pensais que point de vus memoire utilisé ca pourrait devenir gourmand... mais je vais regarder ca de plus pres.
Aussi le fait que je decouvre pas mal de trucs alors je veux pas trop m'embrouiller avec des choses nouvelles.

Non, si je commente la ligne et fais
            myDoc.Save(dataFile);
            myDoc.Load(dataFile);
            RemoveOldRectangles();
            //ProceedDisplay();


Je vois toujours mes anciens Controls, pourtant en debug je vois bien qu'ils sont retirés de la list "this.Controls"
Mais ils restent a l'ecran. Pire ils declenchent toujours les "MouseEnter"

Merci
Messages postés
15134
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
23 novembre 2020
462
Essaye
this.Refresh();
à la fin de RemoveOldRectangles, ça force le formulaire à se redessiner.

D'ailleurs dans cette méthode, la boucle while n'est pas la plus judicieuse.
la boucle for sert à compter et donc est mieux adaptée.

for(int i = ControlsToRemove; i > 0; i++)// dans mon exemple i compte de ControlsToRemove à 1
                 this.Controls.Remove(this.Controls[i]);

this.Refresh();





Whismeril

Salut

Je pense que tu voulais dire un i-- pour la boucle For car ControlsToRemove = le nombre de control a enlever

bref j'ai essayé, avec le refresh, mais ca me donne la meme chose qu'avant

merci de ton aide pourtant

Pardon j'avais mal lu ton commentaire, apres la boucle For

bref j'ai utilisé
            for (int i = ControlsToRemove; i > 0; i--) this.Controls.Remove(this.Controls[IndexControlsToRemove]);  
            this.Refresh();

mais ca ne me bouge pas mes nouveaux lbl
Messages postés
15134
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
23 novembre 2020
462
On va essayer autrement, à l'ajout on va les mettres dans une liste.
C'est cette liste qu'on supprimera par la suite. Par sûr que ça marche.

tu déclares
List<Label> lstLbl = new List<Label> ();


public void DrawRectangle(int Day, int Month, int ID, int Position, string ParaColor)
        {
            Month = RectX(Month);
            Month = Month + (13 * (Position));
            Day = RectY(Day);
            Label lbl = new Label();
            lbl.Name = ID.ToString();
            lbl.Top = Day;
            lbl.Left = Month;
            if (ParaColor "Black") lbl.BackColor Color.Black;
            else if (ParaColor "Green") lbl.BackColor Color.Green;
            else if (ParaColor "Red") lbl.BackColor Color.Red;
            else if (ParaColor "Yellow") lbl.BackColor Color.Yellow;
            lbl.Size = new System.Drawing.Size(10, 10);
            lbl.MouseEnter += lbl_MouseEnter;
            lbl.Click += lbl_Click;
            lbl.MouseLeave += lbl_MouseLeave;
            this.Controls.Add(lbl);
            lstLbl.add(lbl);//ici on ajoute dans la liste
        }



et dans RemoveOldRectangles

foreach(Label lbl in lstLbl)
{
    this.Controls.Remove(lbl);
    lstLbl.Remove(lbl);
}



Whismeril

je pense que j'ai trouvé et je pense que c'est une erreur de debutant ! donc mes excuses si tu as passé du temps pour une telle betise...

quand j'ouvrais la Form fille, je ne fermais pas la Form mere, du coup elle gardait les meme affichages (ne me demande pas pourquoi...)

si je la cache avec this.hide(); avant d'appeller la Form fille, et la rappelle avec Form1.show(); quand je ferme ma Form fille
alors mon affichage est mis a jour

maintenant, y aurait-il moyen de laisser la FormMere ouverte pendant que la FormFille est au premier plan ?
car ca fait bizarre de la chacher totalement et ouvrir une petite fenetre a la place ?


Merci

en fait, je pense que j'utilise pas les bon outils pour passer des valeurs d'une form a l'autre

le code suivant est ma methode, dans ma Form fille, pour passer les valeurs a la Form mere.
        private void buttonSaveAndClose_Click(object sender, EventArgs e)
        {
            Amount = Convert.ToInt32(textBoxEditAmount.Text);
            Notes = textBoxEditPaymentNote.Text;

            Form1 ParentForm = new Form1();
            ParentForm.Show();
            ParentForm.UpdateValuesFromEditPayment(Day, Month, Year, Amount, Notes, ID);
            this.Hide();
        }


comme tu peux voir, je recreer une instance de la Form mere, y aurait pas plus simple ?

merci
Messages postés
15134
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
23 novembre 2020
462
Houla j'ai raté des épisodes!

Recrer une instance n'est pas bon, du coup tu en as deux et ça doit être ça qui te mets la garouille.

Pour le passage de tes valeurs, dans les commentaires du tuto que tu as mis en lien, il y a l'adresse d'un code de bidou.

C'est une méthode qui correspondrait bien a ton utilisation (enfin je pense).

En gros, de form1 vers form2, tu passes les données paramètres du contructeur comme pour une méthode.
Avant d'afficher form2 (.show()), tu t'abonnes a un événement de form2.

Dans form2 tu crées un événement (genre donneesmiseajour) qui par l'intermédiaire d'un delegate ( en gros un modèle de signature de méthode) te permets le passage de valeur à un abonné.

Dans le bouton saveandclose, tu générés l'événement avec les paramètres et tu fermes.

Dans form1 la méthode abonnée récupère les donnees et tout baigne!

Test son code et si tu as des questions n'hésite pas.
Je le connais bien, il m'a servit quand j'ai débuté

Whismeril

Ok, merci. Je vais avancer un peu dans mon programme et je reviendrai sur les points pas trop compris, donc je suis sur d'avoir d'autres questions !

merci encore a plus.

mick