Toon posts:

[VB.NET] ArrayList met controls

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb het voor mekaar gekregen om controls te serialiseren en te deserialiseren in een arraylist.
Deze arraylist bevat dus allerlei controls zoals TextVelden, Buttons, GroupBoxen, etc.

Maar in de arraylist staan niet daadwerkelijk de controls zelf, maar een afgeleide ervan, via het memento patroon!

Ik zal ff toelichten hoe dit in z'n werk gaat, ik heb een textVeld geplaatst op een paneel en deze heeft enkele properties geset:

- databinding
- size
- location
- text
- readonly

Het probleem was dat een control op zichzelf niet te serialiseren is (althans dat heb ik dan aangenomen), dus sla ik deze properties op in een memento class.
Deze memento class houdt dus als het ware de properties vast, en deze class is wel te serialiseren!

De TextVeld heb ik twee methoden extra meegegeven, namelijk createMemento() en setMemento()

createMemento() : Hier word er een instantie van memento gereturned, waarin de waardes staan van de hierboven genoemde properties.
Deze methode word gebruikt bij het serialiseren.

setMemento() : Hier word een memento instantie meegegeven, en worden de properties geset van hierboven.
Deze methode wordt gebruikt bij het deserialiseren.

Stel ik heb nu een meerdere textVelden met verschillende waarde voor de properties, dan maak ik voor ieder textVeld een memento aan, en pleur die in een arrayList.
Als ik dan ga serialiseren, serialiseer ik dus de arrayList.

Bij het deserialiseren, heb ik dus een arrayList met memento classes voor een textVeld. En dan met de setMemento() methode, maak ik weer dezelfde textVelden aan zoals ik ze eerst had.
Dit is allemaal geen probleem.

Maar zodra ik een arrayList serialiseer met verschillende controls, een textVeld en een Button, dan moet ik dus met IF statements gaan checken wat er nu aangemaakt moet worden:
een Button of een textVeld!

Dat IF gebeuren is naar mijn mening niet echt efficient, en zoek dan ook een andere methode om dit te doen?

Ik hoop dat het zo een beetje duidelijk is wat ik bedoel, zo niet vraag het me dan?

  • whoami
  • Registratie: December 2000
  • Nu online
polymorphisme.....

Je kan in je base-class (of in je interface) een abstracte method (of een signature) toevoegen die je overrided in je inherited classes (button, textveld, .... ).
Die overrides hebben dus de specifieke implementatie wat er bij ieder type control moet gebeuren.

Je roept die dan zo aan:
code:
1
2
3
4
foreach( myBaseControl in myArrayListWithDiffControls )
{
    myBaseControl.Serialize();
}


bv.

Als je het niet snapt, dan zoek je best eens eea op ivm OO en polymorphisme dus

Klein voorbeeld:
Stel, je hebt een class Persoon, en je hebt 2 classes 'Werkgever' en 'Werknemer', die beide inheriten van Persoon
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Persoon
{
   public abstract void WatBenIk();
}

class Werkgever : Persoon
{
   public override void WatBenIk()
   {
        MessageBox.Show("Ik ben werkgever");
   }
}

class Werknemwer : Persoon
{
    public override void WatBenIk()
    {
         MessageBox.Show("Ik ben werknemer");
    }
}


Stel, je hebt nu deze code:
code:
1
2
3
4
5
6
7
8
9
10
Persoon[] myList = new Persoon[3];

myList[0] = new Werkgever();
myList[1] = new Werknemer();
myList[2] = new Werknemer();

for(int i = 0; i < 3 ; i++ )
{
    myList[i].WatBenIk();
}


Deze code geeft dus als output:
Ik ben werkgever
Ik ben werknemer
Ik ben werknemer
(Je kan 't ook met interfaces gaan doen, 't is maar wat de beste oplossing is in jouw situatie)

[ Voor 47% gewijzigd door whoami op 25-11-2003 16:37 ]

https://fgheysels.github.io/


Verwijderd

Topicstarter
whoami schreef op 25 november 2003 @ 16:32:
polymorphisme.....

Je kan in je base-class (of in je interface) een abstracte method (of een signature) toevoegen die je overrided in je inherited classes (button, textveld, .... ).
Die overrides hebben dus de specifieke implementatie wat er bij ieder type control moet gebeuren.

Je roept die dan zo aan:
code:
1
2
3
4
foreach( myBaseControl in myArrayListWithDiffControls )
{
    myBaseControl.Serialize();
}


[...]
Ok, maar hier ga je er dus vanuit dat ik weet om wat voor control het gaat, en dat weet ik dus niet! Want ik heb een arrayList met allemaal memento instanties erin, en die bevat altijd dezelfde waardes/properties!

Nu check ik door middel van een if statement op strings, de memento class bevat een propertie ControlSoort, en als die string dan "TextVeld" bevat, dan maakt ie een textVeld aan met de betreffende overige properties, is die string "Button" dan ....

Oftewel jouw verhaal gaat niet op voor mijn probleem, sterker nog ik heb dit al deels gedaan!

  • whoami
  • Registratie: December 2000
  • Nu online
Wel, met die memento-objecten kan je toch hetzelfde realiseren ?

Trouwens, waarom maak je eigenlijk gebruik van memento? Je moet toch geen veranderingen in toestand van die controls bewaren om ze te kunnen bewaren, en je hoeft toch ook niet terug te kunnen gaan naar een vorige toestand? Want daarvoor is memento eigenlijk ontworpen.

https://fgheysels.github.io/


  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 18:08

gorgi_19

Kruimeltjes zijn weer op :9

Is dat kader, is Flyweight misschien niet beter, als we toch over design patterns hebben?
Is Flyweight in dat kader niet beter, als we het toch over design patterns hebben?
zinsbouw gorgi, zinsbouw..... :P

[ Voor 44% gewijzigd door whoami op 25-11-2003 21:45 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


  • whoami
  • Registratie: December 2000
  • Nu online
Memento gebruik je als je een momentopname van de status van een object wilt bewaren, en de mogelijkheid wilt hebben om dat object later in die status te kunnen herstellen.
Aangezien ik er van uitga dat de controls die hier geserialized moeten worden niet echt van staat kunnen (of hoeven) te veranderen, en dat je geen momentopnames wilt maken om later terug te kunnen gaan (undo/redo eigenlijk), lijkt Memento me hier dus niet echt opportuun.

flyweight is hier misschien wel te gebruiken, maar ik heb er geen concrete ervaring mee.

Misschien is een strategy hier wel interessant: afhankelijk van het type object dat je wilt serializeren, gebruik je een andere serializer.

https://fgheysels.github.io/


  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 18:08

gorgi_19

Kruimeltjes zijn weer op :9

Ik begin het verhaal nu enigszins kwijt te raken..

Ik sluit me helemaal bij je aan dat je strategy kan gebruiken als je meerdere verschillende manieren hebt van deserializen, afhankelijk van de control.

Het zou ook kunnen dat het probleem is om heel veel dezelfde controls te hebben, welke eigenlijk maar een paar controls zijn (in de basis), met een paar verschillende eigenschappen, zoals plaats en kleur. In dat geval schijnt een flyweight goed te voldoen. Echter, zelf ook weinig gebruikt; ook weinig toepassingen voor kunnen bedenken (behalve de folders in Windows verkenner :P)

Maar als we toch bezig zijn; is een adapter dan niets? Je laat alle controls dezelfde interface implementeren, waarin de deserializemethod zit. Vervolgens laat je de specifieke implementatie over aan de control zelf.

[ Voor 16% gewijzigd door gorgi_19 op 26-11-2003 20:17 ]

Digitaal onderwijsmateriaal, leermateriaal voor hbo


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

whoami schreef op 26 november 2003 @ 20:12:
Memento gebruik je als je een momentopname van de status van een object wilt bewaren, en de mogelijkheid wilt hebben om dat object later in die status te kunnen herstellen.
Aangezien ik er van uitga dat de controls die hier geserialized moeten worden niet echt van staat kunnen (of hoeven) te veranderen, en dat je geen momentopnames wilt maken om later terug te kunnen gaan (undo/redo eigenlijk), lijkt Memento me hier dus niet echt opportuun.
Ik denk dat hij bedoelt dat hij de huidige info van die buttons op wil slaan. Dus text, kleur, size etc. Maar vraag me af of momento daar idd bedoelt voor is. Maar de techniek die hij gebruikt, is op zich niets mis mee en het enigste dat hij wil is op bassi van 'domme' data weer bij het juiste object terecht te komen. Hij vind een reeks met if-else statements te langzaam en zoekt dus een snellere manier om het juiste object terug te vinden.

Hmm.. er schiet me niet echt een goeie oplossing te binnen. Ik zat te denken aan een key (int) in zo`n momento mee te nemen en dan kan je daarna een switch case doen. Dit vind ik zelf eigelijk een vrij lelijke oplossing.

Misschien dat je de class naam van het object mee kan nemen, en dmv reflectie de juiste classes weer opzoeken?
flyweight is hier misschien wel te gebruiken, maar ik heb er geen concrete ervaring mee.
Flyweight is hier niet praktisch voor omdat je met een flyweight objecten gaat sharen en niet overal een nieuwe voor gaat aanmaken. Bv voor een editor en de karakters. Je gaat niet voor iedere 'a' op het scherm een object aanmaken, maar je maakt eenmalig een a aan voor de hele editor. Als de 'a' dan getekend moet worden, geef je hem de context mee waarin hij getekend kan worden.

Op deze manier loop je niet onnodig veel objecten aan te maken, maar kan je toch op een object ge-orienteerde manier proggen. In zijn geval is dit niet praktisch omdat hij die controls niet wil sharen.
Misschien is een strategy hier wel interessant: afhankelijk van het type object dat je wilt serializeren, gebruik je een andere serializer.
Hij krijgt een hele lading objecten (van verschillende soorten) terug. Aan een strategy heeft hij niets omdat het inlezen niet pluginbaar hoeft te zijn. Als hij de goeie manier heeft gevonden (lees snel), dan is hij klaar. Hij hoeft verder niet echt detail gedrag variabel te maken.

[ Voor 6% gewijzigd door Alarmnummer op 27-11-2003 09:23 ]


  • whoami
  • Registratie: December 2000
  • Nu online
Ik begin me trouwens af te vragen of je hier eigenlijk wel eeo GoF pattern voor nodig hebt.

Om nog eens terug te komen op een eerdere post van me ivm dat polymorfisme;

Je formatter serialiseert objecten, welke informatie er van een object moet geserializeerd moet worden, weet die formatter niet. Je roept hem nl op deze manier aan:
code:
1
myFormatter.Serializer(theStream, anObject);


Het is nl het object zelf die gaat gaan specifieren hoe hij geserialized moet worden, jouw object heeft nl. het Serializable attribuut -dat er dus voor zorgt dat alle public fields geserialized worden- of implementeert de ISerializable interface. Op deze laatste manier ga je dus dmv de GetObjectData method oid gaan specifieren hoe de data geserialized moet worden.
Jouw formatter zal dus gebruik maken van die GetObjectData method (die dus voor ieder type object/control een andere implementatie heeft) om die info te kunnen wegschrijven (in de serialize) of ophalen (in de deserialize).

Ik vraag me dus af waar jij die if-statements enzo nodig hebt ?

https://fgheysels.github.io/


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik geloof om van die data weer terug te komen naar de control.

[edit]
oeps.. Ik zie dat hij ook zat te stoeien om een lijst met controls te serializen.

Daarvoor 1 ding bijzonder handig: single dispatch. Dit kan je op verschillende manieren voor elkaar krijgen (jouw reeks met if else statements, lelijk) polymorfisme (dus een output methode aan het object) of een visitor :P

[ Voor 74% gewijzigd door Alarmnummer op 27-11-2003 09:29 ]


  • whoami
  • Registratie: December 2000
  • Nu online
Alarmnummer schreef op 27 november 2003 @ 09:26:
Ik geloof om van die data weer terug te komen naar de control.
Hmmm, ok. Met de standard Serializers die in .NET zitten, is dat ook geen probleem.

Ik heb ff een klein testje gedaan:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[Serializable]
public abstract class Persoon
{
    
  public string Naam;
  public int    Leeftijd;
    
  public Persoon()
  {         
  }
    
  public abstract string ShowInfo();
}
    
[Serializable]
public class Werknemer : Persoon
{
  public Decimal Loon;
      
  public  override string ShowInfo()
  {
      return this.Naam + " " + this.Leeftijd.ToString() + 
             " loon = " + this.Loon.ToString();       
  }
}
    
[Serializable]
public class Werkgever : Persoon
{
  public int     AantalWn;
  
  public override string ShowInfo()
  {
      return this.Naam + " " + this.Leeftijd.ToString() +
            " aantal wn " + this.AantalWn.ToString();
  }

}


Het serializen gebeurt als volgt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Werknemer       n;
Werkgever       g;
      
BinaryFormatter f = new BinaryFormatter();
FileStream fs = new FileStream(@"c:\sertest.dat", FileMode.Create);
      
Persoon[] blaat = new Persoon[2];
      
n = new Werknemer();
n.Naam = "werknemer";
n.Leeftijd = 30;
n.Loon = 1000;
      
g = new Werkgever();
g.Naam = "Werkgever";
g.Leeftijd = 55;
g.AantalWn = 2;
      
blaat[0] = n;
blaat[1] = g;
      
f.Serialize(fs, blaat);


en het deserializen gebeurt zo:
code:
1
2
3
4
5
6
7
8
9
10
BinaryFormatter f = new BinaryFormatter();
FileStream fs = new FileStream(@"c:\sertest.dat", FileMode.Open, FileAccess.Read);
Persoon[] p = new Persoon[2];
      
p = (Persoon[])f.Deserialize(fs);
      
for( int i = 0; i < p.Length; i++ )
{
  MessageBox.Show(p[i].ShowInfo());
}


En de output is goed; eerst wordt er een werknemer getoond, dan een werkgever.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Ok, ik heb het opgelost, en wel als volgt:

- memento patroon, leek niet nodig te zijn, maar het zou wel kunnen!

- ik heb dus een interface gebruikt, die maar EEN methode heeft namelijk:
code:
1
deserialize(ByVal ctrl As Control)


- deze interface heb ik geimplementeerd in al mijn controls die ik wil serialiseren en deserialiseren.

- Ook implementeren al mijn controls, de ISerializble en override ik dus de GetObjectData() methode

Als ik nu van een panel alle controls die erop liggen wil serialiseren, stop ik ze eerst allemaal een een arrayList, dmv. een simpel for each lusje. Deze word dus weggeschreven naar een file!

Als ik nu de controls weer trug wil hebben, doe ik dat als volgt:

code:
1
2
3
4
5
6
7
8
9
10
11
12
' verkorte code
Dim arrControls as New ArrayList()
Dim bf as new Binary.BinaryFormatter()

' file is al eerder gedeclareerd en bevat dus de 
' geserialiseerde arrayList met controls
arrControls = bf.Deserialize(file)

Dim uc As ucInterface ' dat is dus de interface zoals hierboven beschreven stond
For Each uc In arrControls
      uc.deserialize(uc)
Next


En dat is alles om te bereiken wat ik wou, namelijk GEEN if statements! :D

Ik heb dit gemaakt op basis van de volgende "tip" van whoami _/-\o_ :
Je kan in je base-class (of in je interface) een abstracte method (of een signature) toevoegen die je overrided in je inherited classes (button, textveld, .... ).
Die overrides hebben dus de specifieke implementatie wat er bij ieder type control moet gebeuren.
En wat ik precies heb gedaan is omschreven, nadat ik dat dus al gedaan had, door gorgi_19:
Maar als we toch bezig zijn; is een adapter dan niets? Je laat alle controls dezelfde interface implementeren, waarin de deserializemethod zit. Vervolgens laat je de specifieke implementatie over aan de control zelf.
Ik hoop dat andere mensen er zo ook wat aan hebben! :+

  • whoami
  • Registratie: December 2000
  • Nu online
Hoe ziet jouw implementatie van deserialize er dan uit ?
Ik snap nu nl. niet waarom je die nodig hebt, als je m'n vorige post bekijkt.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Nu online
Als je kijkt hoe het bestand eruitziet dat dmv de standaard Formatters / serializers (in binary format) geserialized werd, dan zie je ook dat er type-informatie opgenomen wordt in het bestand wb de geserializeerde objecten.

https://fgheysels.github.io/

Pagina: 1