C#, donnée et datagridview

Salut les amis!

je suis en train de m’amuser en C#, que je connais tres peu.
J’essaye de faire un petit programme a la con qui gere qq tableau, les affiches, permets de faire des manipulation simples sur les données qu’ils contiennent…
Ya en gros une colonne par mois de l’année + une colonne pour un nom + une colonne qui est la somme des valeurs.
Il y a autant de ligne que l’on veut (en gros chaque ligne est une nouvelle entrée).
Rien que ne pourrait faire excel en somme, mais c’est pour un pote qui ne sait pas se servir d’excel, et comme j’avais envi de me degourdir les doigts, je lui fais sur mesure ^^

Voila, J’ai donc créé une classe ligne, qui contient un tableau de float, un nom, et la somme de valeurs du tableau.
J’ai egalement une classe tableau, qui contient une sortedList, qui va contenir mes lignes (la clef sera le nom de la ligne).
J’ai fait les methode pour ajouter des lignes tout ca, pas de pb.

Ma premiere question est la suivante :
Pour afficher tout ca, j’ai 2 solution : tout faire a la main (je pense en etre capable), mais ca me fera coder “a l’ancienne”, comme je faisais en java ou en C++, en creant tout, et particulierement les interaction ihm. C’est long et fastidieux.
Ou utiliser des nouvelles briques que je sais exister, comme par exemple un DataGridView, et lui associer un BindingSource. Et ca me permet d’apprendre en meme temps les techniques de programation de 2005 et pas continuer comme en 1995 ^^
Ce que j’aimerai faire, c’est que je lie ma classe tableau au datagridview, en implementant une interface sur ma classe, ou en surchargant les methode de creation de ligne et autre. Cela pour que C# appelle les methode d’ajout de ligne de MA classe tableau a moi. Comme ca les données seraient liées et ca m’eviterai de me coder a la main toute les interactions (modification de la valeur d’une case, ajout d’une ligne …).
Le pb, c’est que je sais absoluement pas comment ca marche. Les tutoriaux que j’ai trouvé sur le net me parle de table et autre, mais j’ai pas envi d’aller dans ce sens la.
J’aimerai, en gros, rester maitre de la maniere dont sont gerer les données, mais utiliser un composant tout pret (le datagridview par exemple) pour les afficher et les manipuler.

Voila, si vous pouvez m’aider, je suis preneur ^^

Pour info, voici le code actuel, c’est fait a la va vite en 2h hier soir, j’apprends en meme temps. Soyez donc pas trop servere avec la propreté ^^ Je refondrais le tout quand je serais plus à l’aise avec C#. (!summon Gloppy ^^)

[code]using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Compta
{
static class Program
{
///


/// The main entry point for the application.
///

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ComptaForm comptaForm = new ComptaForm();
Application.Run(comptaForm);

		// Essai à la main pour voir comment ca se comporte
		float[] tab = { 1, 2, 3, 4, 12.354654F, 321, 546, 321, 654, 87, 6524, 321 };
		System.Console.WriteLine("toto\n");

		Ligne maLigne = new Ligne("hop", tab);
		Tableau grostab = new Tableau();

		grostab.addLigne(maLigne);

		maLigne = new Ligne("zup", tab);
		grostab.addLigne(maLigne);
		maLigne = new Ligne("toto", tab);
		grostab.addLigne(maLigne);
		maLigne = new Ligne("gouzi", tab);
		grostab.addLigne(maLigne);
		maLigne = new Ligne("prosper", tab);
		grostab.addLigne(maLigne);
		maLigne = new Ligne("bidule", tab);
		grostab.addLigne(maLigne);
		maLigne = new Ligne("arof", tab);
		grostab.addLigne(maLigne);
		System.Console.WriteLine(grostab.toString());

		Ligne autreLigne = grostab.getLigneByName("bidule");
		autreLigne.setMontantByMonth(Mois.JANVIER, -123);
		System.Console.WriteLine(grostab.toString());

		comptaForm.tableauBindingSource.DataSource = grostab;
	}
}

enum Mois
{
	JANVIER,
	FEVRIER,
	MARS,
	AVRIL,
	MAI,
	JUIN,
	JUILLET,
	AOUT,
	SEPTEMBRE,
	OCTOBRE,
	NOVEMBRE,
	DECEMBRE
}

static public class Constante
{
	// Definition des constantes
	public const int NB_MOIS = 12;
}

}

using System;
using System.Collections;
using System.Text;

namespace Compta
{
class Ligne
{
// constructeurs
public Ligne(String nom)
{
m_nom = nom;
m_tableau = new float[Constante.NB_MOIS];
calculSomme();
}

	public Ligne(String nom, float[] tableau)
	{
		m_nom = nom;
		m_tableau = new float[Constante.NB_MOIS];

		if (tableau.Length == Constante.NB_MOIS)
		{
			for (int i = 0; i < m_tableau.Length; i++)
				m_tableau[i] = tableau[i];
		}

		calculSomme();
	}

	// methode de la classe
	public void calculSomme()
	{
		m_somme = 0;
		for (int i = 0; i < m_tableau.Length; i++)
		{
			m_somme += m_tableau[i];
		}
	}

	// Affichage generique
	public string toString()
	{
		string result;
		
		result = "Nom=[" + m_nom + "] -- Somme=["+m_somme+"] -- Tableau=[";
		for (int i = 0; i < m_tableau.Length; i++)
		{
			result += m_tableau[i].ToString();
			if(i==(m_tableau.Length-1)) 
				result += "]";
			else
				result +=";";
		}
		return (result);
	}

	// Accesseurs
	public string getNom() { return (m_nom); }
	public float getSomme() { return (m_somme); }
	public float getMontantByMonth(Mois mois) 
	{
			return (m_tableau[(int)mois]);
	}
	public void setMontantByMonth(Mois mois, float value) 
	{
		m_tableau[(int)mois] = value;
		calculSomme();
	}

	// Variables membre
	private string m_nom = null;
	private float[] m_tableau;
	private float m_somme;
}

class Tableau
{
	// constructeurs
	public Tableau()
	{
		m_lignes = new SortedList();
	}

	// manipulation des lignes
	public void addLigne(Ligne ligne)
	{
		if(ligne != null)
		{
			m_lignes.Add(ligne.getNom(), ligne);
		}
	}

	public Ligne getLigneByName(string nom)
	{
		if (nom != null)
		{
			int index = m_lignes.IndexOfKey(nom);
			if (index != -1)
				return ((Ligne) m_lignes.GetByIndex(index));
			else
				return (null);
		}
		else
			return (null);
	}

	// Affichage generique
	public string toString()
	{
		string result;
		Ligne ligne;

		result = "Tableau : NbLigne=["+m_lignes.Count+"]\n";
		for(int i = 0; i < m_lignes.Count; i++)
		{
			ligne = (Ligne) m_lignes.GetByIndex(i);
			result += m_lignes.GetKey(i) + ":\t" + ligne.toString() + "\n";
		}
		return (result);
	}

	// accesseur
	public SortedList getLignes() { return m_lignes; }

	// Variable membre
	private SortedList m_lignes = null;
}

}[/code]
A oui derniere question, sur le SortedList : pour typé les données qu’il contient (pour eviter les casts derriere), j’ai voulu le declarer comme ca:

Ca a tres bien marché, sauf qu’ensuite, quand j’ai voulu utiliser la methode GetByIndex, il m’a dit que cette methode existe pas. Comment ca se fait ? j’ai donc abandonné pour avancer en la declarant comme ca :

et je me cogne des cast quand je recupere mes lignes. C’est dommage.

Voila, merci pour votre aide, et desolé si ces questions sont simpliste ^^

Pour le sort d’objects, il faut que tes objects implémentent l’interface IComparable. Et tu peux utiliser ensuite List avec des sorts etc… (je suis pas sur la j’ai pas mon code sous les yeux mais ya une histoire comme ca)

Alors les pro du C#, personne pour m’aider ? :stuck_out_tongue:

Haaaaaaaaaaaa la syntaxe :stuck_out_tongue: Bon je vais jeter un oeil, mais c’est pas exactement la maniere de faire on va dire. La c’est du Java en C# et c’est mooooooche. Je reposte un peu plus tard.

Ca s’est cool de ta part ^^
Clairement, je debute en C#, et j’apprends sur le tas (alors que j’ai pas mal d’experience en java et loo), donc hesite pas pour tout les tips langage que je connais pas :stuck_out_tongue: c’est tout a faire le genre de truc que j’ai envi d’apprendre :stuck_out_tongue:

Bon j’ai refait de zero un truc qui ressemble au coste que tu as code mais avec la syntaxe « C# style » et un embryon de databinding « comme il faut ». Je suis pas un expert du databinding du tout mais j’en connais juste assez pour savoir ou chercher pour le faire « plutot bien ». Donc mattes le code et compare avec ce que tu avais fait.

Je suis pas super content de l’architecture, il y a des trucs pas classes, mais sans savoir dans quel contexte cette API va etre utilisee, c’est completement inutile d’essayer de faire un truc different. Mais bon juste pour dire qu’en pensant en 3/4 scenarios d’utilisation, il y a des trucs a changer dans l’object model pour faire un machin adapte.

Enfin le design a penser c’est que il te faut pas changer ton object model en y introduisant des concepts de UI. Ca c’est le role de la couche de databinding qui est tres liee a ton UI. Le fait que tu ais une classe qui regroupe tes Ligne par exemple, n’a de sens que si t’es pas en train de pousser un concept de UI (je montre plein de lignes a la fois) au niveau object model. Si ton object model a des proprietes speciales qui sont specifiques a un groupe de lignes oui, mais la c’est pas le cas. Tu fais ton object model sans penser en detail a ta UI, tu le rend ideal pour etre un bon object model en soi et apres tu construit une couche de mapping OM/UI avec l’API de databinding. C’est le concept le plus modulaire et la maniere de faire que ton exemple la melangeait un peu les couches.

Enfin bon, le code est la:
http://blog.3deurope.com/data/CBenApp.zip
rien que pour toi :stuck_out_tongue: J’ai fait aussi des trucs pas forcement utile ou adaptees a 100% (ou pas intuitive forcement) juste pour demontrer certains particularites « C# » qui existent pas ailleurs. (Le Array.ForEach ci dessous ou le fait que je hardcode pas le nombre de mois dans une annee par exemple. Ca changera clairement pas, mais ca demontre comment le faire sans).

Juste en tant qu’exemple je te mets la class Ligne.cs ici:

[codebox]

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace CBenApp
{
public class Ligne : IComparable
{
private string nom;
private float[] tableau;
private int NB_MOIS;

public Ligne(string nom)
{
NB_MOIS = Enum.GetValues(typeof(MoisEnum)).Length;
if (nom == null)
throw new ArgumentNullException(nom);
this.nom = nom;
this.tableau = new float[NB_MOIS];

}

public Ligne(string nom, float[] tableau) : this(nom)
{
if (this.tableau == null)
throw new ArgumentNullException(« tableau »);
if (tableau.Length != NB_MOIS)
throw new ArgumentException(« Mauvais nombre de mois dans votre tableau »);
this.tableau = tableau;
}

public string Nom
{
get { return nom; }
}

public float[] Tableau
{
get { return tableau; }
}

public float Somme
{
get
{
// un peu de fun avec les anonymous delegate et les generiques juste pour le plaisir
// plus que par necessitee
float sum = 0f;
Array.ForEach(this.tableau, new Action( delegate(float f) { sum += f; } ));
return sum;
}
}

// un indexer ici, c’est plus zoli
public float this[MoisEnum mois]
{
get
{
return tableau[(int)mois];
}
set
{
tableau[(int)mois] = value;
}
}

public override string ToString()
{
//string builder pour faire propre, les string etant immutable en C#
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendFormat(« Nom=[{0}] – Somme=[{1}] – Tableau=[ », this.Nom, this.Somme);
foreach (float f in tableau)
stringBuilder.AppendFormat("{0};", f);
stringBuilder[stringBuilder.Length - 1] = ‹ ] ›;
return stringBuilder.ToString();
}

public int CompareTo(string other)
{
return String.Compare(this.Nom, other);
}

}

}
[/codebox]

PS un truc a matter et a connaitre aussi c’est que tu peux implementer tes propres indexers. Genre si tableau etait pas un float[] mais sa propre classe avec un tableau de 12 cases, tu pourrais faireun indexer qui prenne un mois directement et pas avoir a le caster en (int) dans un sens et dans l’autre, ce qui, publiquement dans l’API, est franchement pas joli. Donc un truc du genre

public float this[MoisEnum mois] { get { return structureInterneMois.ChopeLaValeurPour(mois); } // tu fais un set si tu veux... }

qui permet de l’utiliser comme talbeauDeFloatCustom[MoisEnum.January] directement…

Merci Beaucoup Glop !

Je regarde tout ca en detail ce soir :stuck_out_tongue:

Ben, qui est content d’apprendre des trucs ^^

Edit :

Juste une question, (surement pas la derniere ^^ et je sais j’avais dit ce soir, mais j’ai pas pu m’empecher de jeter un oeil^^)
Dans le constructeur de Ligne avec un tableau en param, tu as mis « this.tableau = tableau; ». C’est ce que j’avais fait au depart, mais visiblement, l’operateur = fait une copie de pointeur (enfin, ca doit plus s’appeler comme ca, mais ca revient a ca ^^). C’est a dire que le tableau passé en parametre et le tableau de la classe sont finalement le meme, et une modif sur l’un entraine une modif sur l’autre. C’est pour ca que j’avais mis la boucle de recopie du contenu.
Ya un moyen elegant de copier le contenu et pas le pointeur ? (sans faire une surcharge de l’operateur).

Sinon, rapidement, l’effet que me fait c#, c’est que c’est vraiment de la balle. Ca fait plaisir de voir un langage comme ca :stuck_out_tongue: Tu as des tutoriaux bien foutu sous C# pour apprendre vraiment à l’utiliser ? et pas faire du java en C# justement ?

Ben

Ha bah ouai ca va copier le pointeur sur le float[], pas le contenu, si tu veux la copie du contenu faut te la faire a la main, ou avec Array.Copy. Je connais pas vraiment du tuto vu que j’ai appris sur le tas au fur et a mesure en cherchant a droite a gauche sur le web, en lisant du code des autres, donc pas vraiment d’adresse precise ou aller :stuck_out_tongue: Mais mattes le projet que j’ai fait, y a pas mal de trucs un peu subtils qui « font la difference » par rapport a du java en C#, dans les nommages des variables, les properties, etc, etc.

Gloppy, quand je lance ton appli, j’ai un mechant “L’application n’a pas réussi à s’initialiser correctement (0xc0000005). Cliquer sur OK pour arrêter l’application.”. Je cliq sur ok, j’ai de nouveau le message. Je reclic sur ok, et ca bute l’appli.
C’est le portable du boulot, ya peut etre une merde dans la conf. Je ressaye ce soir de maison et je te dis (je crois que le portable du boulot est sous .net 1.1)

Ben

C’est surement du .net 2 (ca m’étonnerai pas que Gloppy ai désinstallé VS2003 chez lui :P).

Pour avoir une erreur comme ça, ca ressemble clairement à un problème en dehors du framework.

Bon Glop, comment dire… Super Mega Merci :stuck_out_tongue:
C’est exactement le genre de truc que je cherchais ! Ca me mets sur les rail, avec des exemples bien comme il faut (maniere de faire et tout). Et surtout, ce que tu m’as montré, c’est pile poil ce que je voulais voir; Comment fait le lien entre ce que je connais, et les nouvelle maniere de faire.
Vraiment, c’est super cool (et ca marche niquel chez moi ^^ je dois avoir une merde avec mon portable)

Je me plonge dans tout ca :stuck_out_tongue:

Ben

De rien :stuck_out_tongue: Oui c’est du .Net 2.0, j’ai toujours 2003, mais seulement pour le devel 360 et plus pour trop longtemps… Apres bye bye, y a pas moyen de revenir a 2003 apres trop de temps passe avec le nouveau.