Sérialisation de Pen [Résolu]

Signaler
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006
-
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006
-
Bonjour,

J'ai un soucis pour enregistrer une arraylist en utilisant la sérialisation binaire.
Mon programme est un outil de dessin (genre Paint) qui permet de dessiner des formes diverses.
J'ai une classe abstraite forme (contenant les champs privé trait (de type Pen) et fond (de type SolidBrush). J'ai également un classe dérivée pour chaque autre forme:
Ellipse :avec le champs rectangle de type Rectangle qui est les coordonnées du rectangle contenant l'ellipse,
Rectangle avec le champs rectangle de type Rectangle,
Polygone: avec un champs tableau_point de typ Point[].

Dans ma classe principale,  je déclare une ArrayList tableau de forme dans laquelle je stocke chaque forme dessinée par l'utilisateur.

Mon problème est que lorsque je veux sérialiser cet ArayList, il y a une erreur à l'exécution me disant que, si j'ai bien compris, le Pen n'est pas marqué comme sérialisable. Quelqun Peut-il me dire comment le rendre sérialisable. Où dois je le marqué comme sérialisable ?

Merci à tous pour vos réponses

11 réponses

Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
17
tout simplement, ne sérialise pas le pen et le solidBrush en eux meme, mais ne serialise que les paramètres dont tu as besoin pour pouvoir reconstruire tes objets.
si par exemple ton pen a besoin pour etre construit d'un bool et de deux int, serialize le bool et les 2 int de ton objet, et a la déserialisation, deserialize ces 3 objets, puis reconstruit ton pen avec le constructeur qui va bien.

je sais pas si cest tres clair....par exemple

seald class ClassA
{
   public int a;
   public int b;
   public bool c;

   public classA (int x, int y, bool z)
   {
      a = x;
//Etc
   }


public class classB
{
private classA Obj;
//blabla, tout le contenu
public new void GetObjectData(SerializationInfo info, StreamingContext             context)
{
info.AddValue ("leint1", Obj.a);
info.AddValue ("leint2", Obj.b);
info.AddValue ("lebool", Obj.c);
}

public classB (SerializationInfo info, StreamingContext ctxt)
{
int a = info.GetValue ("leint1", typeof(int));
//etc pour le reste
Obj = new classA(a, b, c);

}

voila le code est pas du tout complet mais cest pour montrer le principe ;)
Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
17
ta classe doit implémenter l'interface ISerializable. Cela signifie que tu dois avoir la déclaration de ta classe comme ceci :

MaClass : ISerializable

ou si ta classe dérive d'un autre classe mère :

MaClass : MaClassMere, ISerializable

mais cela ne suffit pas, implémenter l'interface signifie ensuite implémenter toutes les méthodes que toblige a implémenter linterface...tu devrais ty retrouver avec l'aide msdn, et si ce n'est pas le cas, n'hesite pas a compiler une fois pour voire les méthodes qui ne sont pas définies et trouver les méthodes que tu dois écrire...
une fois toutes les méthodes de l'interface "surchargées", ta compilation passera ;)
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

Bonsoir leprov,

J'ai déjà chercher de ce côté mais je ne sais pas si c'est ma classe contenant l'arrayList (=classe principale qui derive de forme)  que je doit rendre ISerializable ou bien ma classe abstraite forme_géométraique (qui contient les champs Pen et SolidBrush) ou bien toutes les classes dérivée de FormeGéométrique (Ellipse,Rectangle, etc .. qui sontiennent des champs spécifique à chaque type de forme géométrique).

Pour ce qui est de l'implémentation de l'interface, seule la méthode GetObjectData doit être redéfinie mais hormis le fait d'écrire son prototype, je ne voit pas ce que je dois metrre comme code à l'intérieur.

Je t'avoue que je ne fais pas du Csharp depuis longtemps c'est pour celà que mes questions paraissent peut être un peu simpliste...

Encore merci pour ton aide
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

OK j'ai résolu le problème,

J'ai effectivement dû rendre toute les classes formes géométrique et ses dérivée Iserializable. La surcharge de GetObjectData n'est pas si compliquée que je ne le pensais au début.

Leprov, Encore merci pour ton aide qui m'a été très précieuse

Bonne fin de soirée
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

En  fait, le problème n'est pas encore résolu ... (mais presque j'espère)

Effectivement, la compilation et l'enregistrement se font, par contre, je m'aperçois que les objet Pen et SolidBrush de ma classe Forme_géométriques ne sont pas enregistrés.
Comment faire pour qu'il fassent également partie de la sérialisation et donc de mon enregistrement ?

Merci à tous
Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
17
le Get ne doit permettre que la lecture du fichier serialisé, n'y a t il pas aussi une méthode Set, ou write, ou qqch du style a définir? je nutilise que rarement la sérialisation binaire, je passe plutot par la sérialisation xml en général...a priori si ce nest pas enregistré ca doit etre du au fait que tu nas pas écrit les données, tout simplement...
Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
17
le Get ne doit permettre que la lecture du fichier serialisé, n'y a t il pas aussi une méthode Set, ou write, ou qqch du style a définir? je nutilise que rarement la sérialisation binaire, je passe plutot par la sérialisation xml en général...a priori si ce nest pas enregistré ca doit etre du au fait que tu nas pas écrit les données, tout simplement...
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

Je suppose que tu me parles de la fonction GetObjectData. Après vérification c'est bian la seule à implémenter. J'ai lu que je devait également mettre un constructeur servant lors de la désérialisation (ce qui doit servir de Set vu le code). Pour plus de clarté, voici le code de ces 2 fonctions:

        //Constructeur pour la désérialisation
        public dessin_ellipse (SerializationInfo info, StreamingContext ctxt)
        {
        //Get the values from info and assign them to the appropriate properties
        _rectangle = (Rectangle)info.GetValue("rectangle", typeof(Rectangle));
        _trait_actif = (bool)info.GetValue("trait_actif", typeof(bool));
        _fond_actif = (bool)info.GetValue("fond_actif", typeof(bool));
        }

        //Serialization function.
        #region ISerializable Membres
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            //You can use any custom name for your name-value pair. But make sure                 you

            // then you should read the same with "EmployeeId"
            info.AddValue("rectangle", _rectangle);
            info.AddValue("trait_actif", _trait_actif);
            info.AddValue("fond_actif", _fond_actif);
        }

        #endregion

Ensuite j'enregistre avec:

            sfd.FilterIndex = 1;
            sfd.ShowDialog();

            BinaryFormatter formatter = new BinaryFormatter();
            FileStream fs = new FileStream(sfd.FileName, FileMode.OpenOrCreate,                 FileAccess.Write);
            formatter.Serialize(fs, tableau_formes);
            fs.Close();

Et je ouvre le fichier avec
            ofd.FilterIndex = 1;
            ofd.ShowDialog();
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream fs = new FileStream(ofd.FileName, FileMode.Open,                             FileAccess.Read);
            tableau_formes.Clear();
            tableau_formes.AddRange((ArrayList)formatter.Deserialize(fs));
            fs.Close();

Voilà c'est peut être plus clair comme ça...
Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
17
et quel est exactement le probleme avec ce code? peux tu détailler un peu plus? jai un peu de mal a suivre le probleme avec ton pen et ton solidbrush.. ;)
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

Bon je vais essayer d'être plus clair. Pour commencer, il manque effectivement dans le code ci-dessus la sérialisation de mon Pen et mon SolidBrush. Le revoici donc avec les modifications que j'ai faites et avec plus de détails:

Classe forme géométrique
[Serializable]
    abstract class Forme_géométrique :ISerializable
    {
        //champs
        private Pen _trait;
        private SolidBrush _fond;

        //Constructeurs
        //blablabla

        //propriétés pour l'accès aux champs
        //blablabla

        //Constructeur pour la désérialisation
        public Forme_géométrique (SerializationInfo info, StreamingContext ctxt)
        {
        //Get the values from info and assign them to the appropriate properties
        _trait = (Pen)info.GetValue("trait", typeof(Pen));
        _fond = (SolidBrush)info.GetValue("fond", typeof(SolidBrush));
        }

        //Serialization function.
        #region ISerializable Membres

        public void GetObjectData(SerializationInfo info, StreamingContext            
        context)
        {
            //You can use any custom name for your name-value pair. But make                     sure you
            //read the values with the same name
            info.AddValue("trait", _trait);
            info.AddValue("fond", _fond);
        }
        #endregion
    }

//classe ellipse
    [Serializable]
    class dessin_ellipse : Forme_géométrique, ISerializable
    {
        //champs
        private Rectangle _rectangle;
        private bool _trait_actif;
        private bool _fond_actif;

        //propriétés pour l'accès au champs
        blablabla

        //constructeurs
       blablabla

        //Constructeur pour la désérialisation
        public dessin_ellipse (SerializationInfo info, StreamingContext ctxt)
        {
        //Get the values from info and assign them to the appropriate properties
        base.trait = (Pen)info.GetValue("trait", typeof(Pen));
        base.fond = (SolidBrush)info.GetValue("fond", typeof(SolidBrush));
        rectangle = (Rectangle)info.GetValue("rectangle", typeof(Rectangle));
        _trait_actif = (bool)info.GetValue("trait_actif", typeof(bool));
        _fond_actif = (bool)info.GetValue("fond_actif", typeof(bool));
        }

        //Serialization function.
        #region ISerializable Membres

        public new void GetObjectData(SerializationInfo info, StreamingContext             context)
        {
            //You can use any custom name for your name-value pair. But make                 sure  you
            // read the values with the same name
            info.AddValue("trait", base.trait);
            info.AddValue("fond", base.fond);
            info.AddValue("rectangle", _rectangle);
            info.AddValue("trait_actif", _trait_actif);
            info.AddValue("fond_actif", _fond_actif);
        }
        #endregion
    }

//Fenêtre principale
    public partial class Fenêtre_principale : Form
    {
        //ArrayList contenant les formes du dessin
        ArrayList tableau_formes = new ArrayList();

        private void oEnregistrer_Click(object sender, EventArgs e)
        {
            sfd.FilterIndex = 1;
            sfd.ShowDialog();

            BinaryFormatter formatter = new BinaryFormatter();
            FileStream fs = new FileStream(sfd.FileName, FileMode.OpenOrCreate, FileAccess.Write);
            formatter.Serialize(fs, tableau_formes);
            fs.Close();
            panel_dessin.Invalidate();
        }

        private void oOuvrir_Click(object sender, EventArgs e)
        {
            ofd.FilterIndex = 1;
            ofd.ShowDialog();
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read);
            tableau_formes.Clear();
            tableau_formes.AddRange((ArrayList)formatter.Deserialize(fs));
            fs.Close();
            panel_dessin.Invalidate();
        }
}

Pour résumé, mon solidBrush et mon Pen font partie d'une classe de base (Forme_géométrique) et de cette classe dérive d'autres classes dont Ellipse qui contient les champs Pen et SolidBrush de sa classe de base ainsi que 3 autres champs (1 Rectangle, 2 Bool).

Avec ce code, j'ai une erreur à lors de l'enregistrement du fichier:
Le type 'System.Drawing.Pen' dans l'assembly 'System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' n'est pas marqué comme sérialisable.

Effectivement je n'ai pas marqué le type System.DrawindPen comme sérialisable car il faudrait pour cela que j'accède à la classe Pen (Peut être hériter de celle ci pour pouvoir marqué la classe héritée de serializable) mais le problème est que cette classe est scellée et ne peut dons pas être héritée.

Est-il possible de marqué la classe Pen comme sérialisable avec un autre moyen ?

Pour info: le code de mon précédent message (qui ne tenait pas compte de la sérialisation du Pen et du Solid Brush) fonctionnait parfaitement hormis que le Pen et Solid Brush n'était pas enregistrer. Mes formes avais dons toutes la même couleur lors de l'ouverture (noir)

Voilà, j'espère que j'ai pas été trop long mais c'est pour être certain de te donner tous les élément dont tu as besoins

Merci encore pour tes réponses
Messages postés
7
Date d'inscription
lundi 12 juin 2006
Statut
Membre
Dernière intervention
13 juin 2006

Super ça fonctionne.

J'ai erffectivement sérialisé séparément les champs de couleur et d'épaisseur du trait de mon Pen. Ce qui fesait égélement planté la compilation, c'est qu'une couleur ne peut être sérialisée que quand elle est au format RVB sinon elle n'est pas enregistrée.

Merci beaucoup pour ton aide, sans toi je serai toujours entrain de me casser la tête