Benutzer mit den meisten Antworten
NullReferenceException in Events nach XMLSerialize

Frage
-
Hallo zusammen,
ich schreibe gerade ein Programm, wo ich Elemente (die päter grafisch gerendert werden) in eine Liste hinzufüge. Nach dem hinzufügen in der Liste löse ich ein Event aus, um die Grafiken zu aktualisieren.
Dies funktioniert soweit ganz gut, jedoch wenn ich zuvor gespeicherte Elemente aus einer XML-Datei lade und anschliessend ein Element in der Liste hinzufüge, so bekomme ich immer eine NullReferenceException, wenn ich das Event auslöse.
Ich füge hier mal den wichtigen Code hinzu:
private void LoadXmlFile_Click(object sender, EventArgs e)
{
openFileDialog.ShowDialog();
if (openFileDialog.FileName == null) return;
XmlSerializer ser = new XmlSerializer(typeof(MapElements));
StreamReader sr = new StreamReader(openFileDialog.FileName);
MapElements newElements= (MapElements)ser.Deserialize(sr);
sr.Close();
MapWindow newMap = new MapWindow(newElements.Size);
newMap.Map = newElements;
newMap.MdiParent = this;
newMap.WindowState = FormWindowState.Maximized;
newMap.Show();
}
/* Class: MapWindow */
public MapWindow(Size mapSiize)
{
InitializeComponent();
this.size=mapSize;
map = new MapElements();
graph = picMap.CreateGraphics();
renderer = new RenderEngine(graph); //picMap Events
initializeEvents();
}
// Initializes all events
private void initializeEvents()
{
this.map.creatureAdded += new MapElements.CreatureEventHandler(map_creatureAdded);
}
/*Class: MapElements */
#region Events
public event CreatureEventHandler creatureAdded;
#endregion
public void addCreature(AbstractCreature creature)
{
if (!this.creatures.Contains(creature))
this.creatures.Add(creature);
creatureAdded(creature);
}
Laut Debugger ist der Aufruf von creatureAdded == null. Der Parameter creature ist != null.
Ich hoffe mir kann jemand helfen.
Ciao Kostarsus
- Bearbeitet Kostarsus Dienstag, 24. Mai 2011 15:52
Antworten
-
Hallo Kostarsus,vielen Dank für deine Mail. Ich habe jetzt endlich heute mal die Zeit gefunden, mir dein Projekt mal anschauen zu können. Und ich habe deinen Fehler (durch einfaches Debuggen!!!) gefunden.
Tipp: Verwende für das Projekt WPF. Sparst dir einen haufen Code und hast mit den WPF deutlich mehr möglichkeiten. Zudem werden die WPF Hardwarebeschleunigt ;)Dein Problem liegt hier:Hier musst du übrigens den StreamReader nach dem schliessen noch disposen, sonst erzeugst du ein Memleak. Da ein Reader durchaus auch mal mit eine Exception abrauchen kann, würde ich dir das using statement empfehlen. Das disposed dein Objekt automatisch. Auch dann wenn beim Lesen eine Exception auftritt. Ist also wie ein try-finally Block.private void ladenToolStripMenuItem_Click(object sender, EventArgs e) { if(openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if(openFileDialog.FileName == null) { return; } XmlSerializer ser = new XmlSerializer(typeof(MapElements)); StreamReader sr = new StreamReader(openFileDialog.FileName); MapElements newElements = (MapElements)ser.Deserialize(sr); sr.Close(); MapWindow newMap = new MapWindow(newElements.Size); newMap.Map = newElements; newMap.MdiParent = this; newMap.WindowState = FormWindowState.Maximized; newMap.Show(); } }
Nun zu deinem Eigentlichen Problem:
Du deserialisiert deine Objekte (hängst auch die EventHandler an die Events) und erzeugst danach ein neues MapWindow. Wenn du das erzeugst, erzeugst du natürlich auch den Event neu, andem nun KEIN EventHandler mehr dranhängen.Ich hoffe ich konnte dir bei diesem einen Problem helfen, aber du wirst über kurz oder lang noch auf mehr stoßen. Insgesamt wirkt das Projekt leider sehr unstrukturiert, auch im Code. Was aber schon bei kleineren Projekte bereits ein muss ist, da du sonst nach einer bestimmten Zeit/LoCs selbser nicht mehr durchblickst. Fehler wie der von dir Angefragte sind ein Symptom davon.Ich hoffe ich konnte dir weiterhelfen. Solltest du noch Fragen haben, dann helfe ich dir natürlich gerne ;)Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 8. Juni 2011 10:30
Alle Antworten
-
Hallo Kostarsus,
sorry, aber aus diesem unformatierten Codewirrwar ist nun wirklich nicht viel zu erkennen. Formatiere doch bitte mal den Code, damit dort mal was zu erkennen ist.
Nur mal so ins blaue gegriffen: Du prüfst dein Event nicht auf null. Du musst ein Event immer auf null prüfen, bevor du es feuerst.
public void Foo() { ... if(this.EinEvent != null) { this.EinEvent(this,EventArgs.Empty); } ... }
Ach und noch was! Ich weiss jetzt nicht, ob du deinen Code diesbezüglich für dein Post gekürtzt hast, aber das Graphics Objekt das du dir per picMap.CreateGraphics() erzeugst, solltest du unbedingt Disposen wenn du es nicht mehr benötigst. Sonst erzeugst du jedesmal ein Memleak. ;)
Solltest du noch fragen haben...immer gerne zu!
Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
-
Sorry,
ich nehme an, dass die Formatierung durch die nachträgliche Bearbeitung des Beitrages verloren ging.
Dass die Exception ausgelöst wird verstehe ich ja. Du hast Recht, dass das Event == null ist. Was ich aber nicht verstehe ist, wieso das Event== null ist.
Rufe ich das Fenster ohne vorheriger Deserialisierung auf, so ist das Event gefüllt.
Die Events werden in beiden Fällen gleich initialisiert (von der Klasse MapWindow). Den einzigen Unterschied den ich sehe, ist dass die MapElemeents anders erzeugt werden.
Im einen Fall über den normalen new-Operator im anderen Fall eben durch die Deseriialisierung. Ob dies damit zusammenhängt? Und falls ja, gibt es ein Workaround?
Ciao Kostarsus
-
Hi Kostarsus,
so ist es schon viel besser :)
Ein Event ist null, wenn noch keine Delegate also noch kein EventHandler dranhängt, der das Event behandelt. Du wirst die EventHandler nach dem Deserialisieren noch per Hand an die Events ranhängen müssen.
Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++
- Als Antwort vorgeschlagen Holger M. Rößler Dienstag, 24. Mai 2011 16:01
- Nicht als Antwort vorgeschlagen Holger M. Rößler Dienstag, 24. Mai 2011 16:01
-
Mhm,
also das Delegate habe ich MapElements deklariert (nur vergessen einzufügen ;-)
public delegate void CreatureEventHandler(AbstractCreature creature);
Die Zuordnung des Events mache ich ja in der Klasse MapWindow (Implementierung steht oben).
Habe ich noch etwas vergessen?
Ciao Kostarsus
-
Hallo Kostarsus,
wer horcht denn auf das "creatureAdded" Event?
Hier nur so als Tipp: Das .net Famework kennt bereits eine Collection, die Änderungen an deren Items per Event meldet. Vielleicht solltest du diese Verwenden, dann ersparst du dir auch den ganzen Zirkus.
Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++ -
Das MapWindow horcht auf das Event. Dort habe ich ja auch die methode initializeEvents und die Methode hinzugefügt, welche die Aktionen beim Auftritt des Events durchführt.
Wie gesagt, wenn ich nicht deserialisiere funktionniert alles. Nur nach der Deserialisieerrung ist das Event == null.
-
Hallo Kostarsus,
hast du die Möglichkeit mir dein Projekt mal zu schicken? Dann kann ich mir das Programm mal RICHTIG ansehen.
Dann schicke es bitte an holger.roessler@web.de. Danke :)
Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++- Bearbeitet Holger M. Rößler Mittwoch, 25. Mai 2011 13:15 E-Mail Adresse hinzugefügt
-
Hallo Kostarsus,vielen Dank für deine Mail. Ich habe jetzt endlich heute mal die Zeit gefunden, mir dein Projekt mal anschauen zu können. Und ich habe deinen Fehler (durch einfaches Debuggen!!!) gefunden.
Tipp: Verwende für das Projekt WPF. Sparst dir einen haufen Code und hast mit den WPF deutlich mehr möglichkeiten. Zudem werden die WPF Hardwarebeschleunigt ;)Dein Problem liegt hier:Hier musst du übrigens den StreamReader nach dem schliessen noch disposen, sonst erzeugst du ein Memleak. Da ein Reader durchaus auch mal mit eine Exception abrauchen kann, würde ich dir das using statement empfehlen. Das disposed dein Objekt automatisch. Auch dann wenn beim Lesen eine Exception auftritt. Ist also wie ein try-finally Block.private void ladenToolStripMenuItem_Click(object sender, EventArgs e) { if(openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if(openFileDialog.FileName == null) { return; } XmlSerializer ser = new XmlSerializer(typeof(MapElements)); StreamReader sr = new StreamReader(openFileDialog.FileName); MapElements newElements = (MapElements)ser.Deserialize(sr); sr.Close(); MapWindow newMap = new MapWindow(newElements.Size); newMap.Map = newElements; newMap.MdiParent = this; newMap.WindowState = FormWindowState.Maximized; newMap.Show(); } }
Nun zu deinem Eigentlichen Problem:
Du deserialisiert deine Objekte (hängst auch die EventHandler an die Events) und erzeugst danach ein neues MapWindow. Wenn du das erzeugst, erzeugst du natürlich auch den Event neu, andem nun KEIN EventHandler mehr dranhängen.Ich hoffe ich konnte dir bei diesem einen Problem helfen, aber du wirst über kurz oder lang noch auf mehr stoßen. Insgesamt wirkt das Projekt leider sehr unstrukturiert, auch im Code. Was aber schon bei kleineren Projekte bereits ein muss ist, da du sonst nach einer bestimmten Zeit/LoCs selbser nicht mehr durchblickst. Fehler wie der von dir Angefragte sind ein Symptom davon.Ich hoffe ich konnte dir weiterhelfen. Solltest du noch Fragen haben, dann helfe ich dir natürlich gerne ;)Viele Grüße
Holger M. Rößler
Viele Grüße Holger M. Rößler ++++++++++++++++++++++++++++++++++++++++++++++++++ Kaum macht man es richtig, schon funktioniert es ++++++++++++++++++++++++++++++++++++++++++++++++++- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 8. Juni 2011 10:30