| 

.NET C# Java Javascript Exception

3
Hallo Zusammen,

Ich versuche hier gerade krampfhaft ein Windows.Forms.Panel einer Collection hinzuzufügen.
Das funktioniert auch augenscheinlich, allerdings scheit er nur eine Referenz des Panels zu nehmen.

Bsp.:
Panel mit 1 Control -> myCollection.add (Panel)
dann füge ich panel ein weiteres Control hinzu (Panel.Controls.add(weiss der Fuchs))
Panel mit 2 Controls -> myCollection.add (Panel)

Wenn man die gespeicherten Panels in der Collection vergleicht haben jetzt beide 2 Controls...

Wie kann ich der Collection eine neue Instance des aktuellen Panels geben?

Vielen Dank,
Daniel
04.08.2011
schlumpfger 288 1 8
7 Antworten
3
Hallo schlumpfger,

das hast Du bereits richtig erkannt. System.Windows.Forms.Panel ist ein Referenztyp. Aus diesem Grund sind die beiden Panels in Deiner Collection dieselbe Instanz, denn über Deine Panel-Referenz bearbeitest Du immer dieselbe Instanz, der Collection ist es aber egal, ob Du mehrmals dieselbe Referenz einfügst.

Ich sehe folgende Abhilfe:

  • Entweder du machst Dein Panel deep-cloneable, d.h. wenn Du eine Kopie möchtest, um weitere Controls einzufügen, klonst Du das Panel samt seiner Controls. Das ist aber massig Arbeit und wird immer wieder Pflege brauchen. Mein Rat: Don't do it!
  • Du gehst eine Metaebene weiter und baust nicht die Controls zusammen, sondern Bauanleitungen. Hier könnte Dich das Builder Pattern oder das Prototype Pattern weiterbringen. Nachdem Du Bauanleitungen hinterlegt hast, kannst Du beliebig viele Instanzen "bauen" lassen, die dann gleich aussehen aber nicht mehr dieselbe Referenz sind.

Eventuell gibt es auch noch andere Lösungsvarianten. Wenn Du Deine Frage etwas überarbeitest und den Anwendungsfall genauer spezifizierst, kann man nochmal drüber nachdenken.


EDIT Mit Bezug auf Deinen Nachtrag:
Wenn Du ein Undo implementieren möchtest, dann sehe ich noch eine andere Möglichkeit:
Statt das Objekt in einem bestimmten Zustand zu speichern (z.B. in deiner Collection), speicherst Du die Aktionen (Command), die durchgeführt wurden. Folgendes Fallbeispiel:

1. cmd1 = NewPanelCommand --> Panel-Objekt
2. cmd2 = AddButtonCommand(Panel) --> 1.Button im Panel
3. cmd3 = AddButtonCommand(Panel) --> 2.Button im Panel
4. cmd3.Undo() --> 2. Button wird wieder aus Panel entfernt
5. cmd2.Undo() --> 1.Button wird entfernt, panel wieder leer
...

Dafür passt ein Command Pattern hervorragend.

Viel Erfolg
Florian
04.08.2011
ffordermaier 8,4k 3 9
1
Vielen Dank für die Überlegungen.

Im Prinzip geht es um eine UNDO Funktion. In der Collection wird (bzw. soll) vor jeder Änderung der aktuelle Stand des Panels gespeichert. Die Controls auf dem Panel werden dynamisch per später Bindung hinzugefügt.

Ein Bauanleitung habe ich in der aktuellen Variante als XML vorliegen und kann mir das auch so merken. Das Problem an Bauanleitung ist nur, dass etwas nach dieser Anleitung erst noch gebaut werden muss, und das braucht Zeit. Sprich, das Leeren des Panels, das Erstellen der Controls und das setzen der entsprechenden Eigenschaften. Das ist bei 3 Controls auf dem Panel nicht schlimm, bei 100 dauert das aber schon mehrer Sekunden. Das ist bei einer Undo-Funktion nicht besonders schön. Deshalb der Gedanke sich gleich das Panel (als neue Instanz mit den aktuellen Controls) zu merken und in einer Collection zu speichern...

Man könnte sich natürlich auch die Rferenz auf die Controls merken. Aber die dynamischen Controls können auch wieder gelöscht werden, und damit ist die Referenz für Undo futsch.
04.08.2011
schlumpfger 288 1 8
Hab meine Antwort editiert, siehe oben.
ffordermaier 04.08.2011
0
bitte löschen, war nicht die Antwort auf die Frage.
04.08.2011
KN 1,7k 1 8
KN 1,7k 1 8
0
Spricht das, was du machen möchtest, nicht eher dafür, anstatt eines Panels ein UserControl zu nehmen?
04.08.2011
KN 1,7k 1 8
0
Hallo Zusammen,

Das Speichern der Aktionen wäre eine Möglichkeit, löst aber mein Problem nicht. Das Setzen der Eigenschaften frisst lt. Analyse die meiste Zeit und kommt meiner bisherigen Lösung gleich.

Die Vewendung eines usercontrol habe ich auch probiert als <IClonable>. Anschliessend habe ich das Usercontrol als serialisierbar gekennzeichnet. Es kracht dann aber bei den darauf plazierten Controls die wiederum nicht serialisierbar sind. Da ich nicht weiss welche Controls (ActiveX, Windows Form, Usercontrol) da kommen hilft nichtmal ein kapseln.

Ich denke, ich muss einfach die Lösch- und Ladezeit in Kauf nehmen. Sonst mache ich mir wirklich eine never ending Baustelle auf...

Vielen Dank für eure Ideen.
05.08.2011
schlumpfger 288 1 8
Kannst Du kurz erläutern, warum die Aktionsaufzeichnung als Undo-Mechanismus Dein Problem nicht löst?
ffordermaier 05.08.2011
0
Einmal weil die Variante nicht mit gelöschten Controls umgehen kann. Zum Zweiten fahre ich ja wie bereits geschrieben eine ähnliche Lösung, wo ich mir den Bausatz des Panels komplett speichere mit den von mir benötigten Eigenschaften.

Ich sehe ein Problem bei der Abfolge:

Control hinzufügen
Eigenschaft1 Control ändern
Eigenschaft2 Control ändern
Eigenschaft3 Control ändern
Control löschen

Wenn jetzt ein Undo kommt muss ich mühsam das Control wieder erstellen und die Eigenschaften sind dann auch weg. Da ein UNDO ja heisst einen Schritt zurückgehen...
05.08.2011
schlumpfger 288 1 8
Hab eine neue Antwort geschrieben, weil hier der Platz etwas kanpp ist und keine Formatierungen zulässt.
ffordermaier 05.08.2011
0
Hallo schlumpfger,

Ok, ich verstehe. Aber auch das Löschen kriegen wir in den Griff.

Wenn der Benutzer etwas löscht, muss das ja für Dich bzw. die Applikation nicht heißen, dass es wirklich gelöscht wird. Wenn es nämlich vom Benutzer "gelöscht" wird, kann er danach auch keine Änderungen mehr daran vornehmen. Also lässt Du es für den User nur so aussehen, als ob es gelöscht wurde, packst es aber effektiv einfach (so wie es gerade ist, damit hast Du seinen State quasi eingefroren) auf die Seite (irgendein Container). Ein Undo eines Löschvorgangs ist dann nichts anderes als ein Lookup im Container und Wiedereinfügen des Controls in sein ParentControl.
Für die Zwischenschritte arbeitest entweder über Aktionsaufzeichnung oder Bauplan.

Damit Dir das Ganze nicht irgendwann speichermäßig um die Ohren fliegt, würde ich keine beliebige Undo-Tiefe erlauben, sondern sie in einer Art Ringpuffer auf eine gewisse empirisch zu bestimmende Anzahl einschränken.

Ich hoffe das hilft weiter.
Gruß
Florian
05.08.2011
ffordermaier 8,4k 3 9

Stelle deine Collections-Frage jetzt!