Veröffentlicht 11. Oktober 20168 j Moin! Ich habe tatsächlich zum ersten mal (außerhalb des Schulunterrichts) mit 2 Klassen zu tun und wollte (auch wenn mein Ausbilder sagt ich bin kein AE und kann globale Variablen benutzen) Variablen mithilfe von Methoden hin und her schieben. Jetzt habe ich mir mit dem was ich gelernt habe und mit dem was ich im Internet gefunden habe etwas zusammen gebastelt das 1. glaube ich keiner mehr versteht 2. sich gar nicht erst kompilieren lässt wegen oben genanntem Fehler Meine 2 Klassen sind 2 Form-Anwendungen, die eine als Hauptanwendung und die andere quasi als "Settings-Fenster" das über die Menüleiste aufgerufen werden kann. In der Aufrufliste kann ich sehen welche 2 Funktionen sich da verhaken, weiß aber nicht warum weil mir noch das große Bild der Programmierung fehlt. Hier der Teil der Settings.cs: public partial class Settings : Form { string iniText; public Settings() { InitializeComponent(); Form1 form1 = new Form1(); //das hier wird immer wieder aufgerufen iniText = form1.GetIniText(); } und das hier von meinem Form1.cs public partial class Form1 : Form { //string iniText; string iniPathToPDF; string iniPathToCSV; string iniPathToPCL; string iniPrintPDF; string iniPrinter; string iniPrintserver; string iniText; Settings form2 = new Settings(); //hier sagt es wird immer wieder aufgerufen public Form1() { InitializeComponent(); try { ReadIniFile(); //create Event for Seetings-Close form2.FormClosed += Form2_FormClosed; } catch { MessageBox.Show("Initialisierung der ini-Datei fehlgeschlagen"); } Ich kann meinen Breakpoint nicht da ansetzen wo es auftritt sonst hätte ich das vielleicht irgendwie nachvollziehen können. Die 2 markierten Stellen habe ich eingefügt um damit Funktionen der jeweils anderen Klasse aufzurufen zu können - ist das falsch? Kann sich jemand meiner annehmen und mir das erklären? Grüße Tician Bearbeitet 11. Oktober 20168 j von Tician
11. Oktober 20168 j Du legst immer wieder in einem Objekt der einen Klassen ein Objekt der anderen Klasse an. Damit hast du dir die Exception gebaut. Die Zuweisung im Konstruktur bzw. die Initialisierung des Members werden immer beim Konstruieren eines Objekts ausgeführt. Nutze statt dessen man einen Setter.
11. Oktober 20168 j Hallo Tician. Verstehe ich es richtig, dass du lediglich über Form1 die Settings-Form aufrufen möchtest, welche dann die dort eingegeben Werte zurück an Form1 liefert? Was macht zudem GetIniText()? Wo rufst du die Settings-Form auf? Bearbeitet 11. Oktober 20168 j von Panawr
11. Oktober 20168 j Lösung Das Problem ist, du rufst die Konstruktoren immer wieder neu auf. Du hast hier ein Zirkelschluss produziert. Wenn du Settings instanziierst, wird im Konstruktor Form1 instanziiert und Form1 instanziiert wiederrum Settings, usw. usw. Ich nehme mal an, dass Form1 dein Hauptfenster ist und in Form1 Settings aufgerufen werden soll. Settings darf von Form1 nichts wissen. Wozu auch? Und wenn Settings unbedingt Form1 kennen muss, dann musst du Form1 als Abhängigkeit reinreichen. public Settings(Form mainForm) { InitializeComponent(); this.mainForm = mainForm iniText = form1.GetIniText(); } Aber selbst das würde ich nicht tun. Ich würde beim Aufruf von Settings den iniText reinreichen: public Settings() { InitializeComponent(); } public string IniText { get { return this.iniTextTextBox.Text; } set { this.iniTextTextBox.Text = value; } } Dann würde ich Settings so aufrufen: Settings settings = new Settings(); settings.IniText = "foo bar"; settings.Show(); Damit ist Settings nicht von Form1 abhängig.. Dies ist jetzt nur eine abgespeckte Version, um das Prinzip etwas zu verdeutlichen. Wenn du es wirklich elegant lösen willst, dann informiere dich über MVP (Model-View-Presenter).
11. Oktober 20168 j Autor Das ist etwas komplizierter, ich versuche mal meinen Gedankengang und etwas mehr Code dazu zu veröffentlichen: Wenn das Programm gestartet wird läd Form1 Einstellungen aus einer ini-Datei, speichert diese in Variablen und schreibt diese in labels von Form2 (Settings-Fenster) mit der WriteIniToLabels() Methode. Wenn jetzt aber Form2 über das Menü aufgerufen wird gibt es dort Möglichkeiten die EInstellungen zu ändern. Wenn Form2 geschlossen wird muss Form1 die Einstellungen neu auslesen. Form1 relevante Ausschnitte: public partial class Form1 : Form { //string iniText; string iniPathToPDF; string iniPathToCSV; string iniPathToPCL; string iniPrintPDF; string iniPrinter; string iniPrintserver; string iniText; Settings form2 = new Settings(); public Form1() { InitializeComponent(); try { ReadIniFile(); //create Event for Seetings-Close form2.FormClosed += Form2_FormClosed; } catch { MessageBox.Show("Initialisierung der ini-Datei fehlgeschlagen"); } } private void Form2_FormClosed(object sender, FormClosedEventArgs e) { ReadIniFile(); } public void ReadIniFile() { //ini-Datei lesen iniText = File.ReadAllText("settings.ini"); SetIniText(iniText); //PDF und CSV und PCL Pfad lesen und ausgeben Regex reg1 = new Regex("(?<=PathToPDF\\=).+"); Regex reg2 = new Regex("(?<=PathToCSV\\=).+"); Regex reg4 = new Regex("(?<=PathToPCL\\=).+"); Match pdfPath = reg1.Match(iniText); Match csvPath = reg2.Match(iniText); Match pclPath = reg4.Match(iniText); iniPathToPDF = Convert.ToString(pdfPath); iniPathToCSV = Convert.ToString(csvPath); iniPathToPCL = Convert.ToString(pclPath); //Write ini-Settings to Form2-Labels form2.WriteIniToLabels(iniPathToPDF, iniPathToCSV, iniPathToPCL); //Drucker auslesen Regex reg5 = new Regex("(?<=Printer\\=).+"); Regex reg6 = new Regex("(?<=Printserver\\=).+"); Match printer = reg5.Match(iniText); Match printserver = reg6.Match(iniText); iniPrinter = Convert.ToString(printer); iniPrintserver = Convert.ToString(printserver); //Checkbox-status lesen und aktualisieren Regex reg3 = new Regex("(?<=PrintPDF\\=).+"); Match pdfCheck = reg3.Match(iniText); iniPrintPDF = Convert.ToString(pdfCheck); if (iniPrintPDF == "0") { checkBox1.Checked = false; } else { checkBox1.Checked = true; } } string newIniText; public void SetIniText(string iniText) { newIniText = iniText; } //To get ini from Settings public string GetIniText() { return newIniText; } Form2 relevante Ausschnitte: public partial class Settings : Form { string iniText; public Settings() { InitializeComponent(); Form1 form1 = new Form1(); iniText = form1.GetIniText(); } //Method for Form1 public void WriteIniToLabels(string text1, string text2, string text3) { label1.Text = text1; label2.Text = text2; label3.Text = text3; } Das ist alles nur Idee und zusammengeschrieben wie es mir in den Sinn kam, ich glaube ein paar Dinge brauch ich gar nicht mehr also sucht da nicht unnötig nach Fehlern die finde ich selbst sobald ich es kompilieren kann (hoffe ich^^). Erstmal muss der StackOverflow raus und ich weiß nicht wie ich es anders machen kann, dazu fehlt mir die Erfahrung.
11. Oktober 20168 j Autor Hoppla zu der Frage wo die Form2 aufgerufen wird, das hier steht noch in Form1, wie gesagt das ist eine Menü-Leiste private void settingsToolStripMenuItem1_Click(object sender, EventArgs e) { form2.Show(); }
11. Oktober 20168 j Bin leider kein riesen Experte in Windows Forms, aber das dürfte doch mit der ersten Methode von Whiz-zarD funktionieren, auch wenn nicht unbedingt super schön. public Settings(Form mainForm) { InitializeComponent(); this.mainForm = mainForm iniText = this.mainForm.GetIniText(); } Das Event private void Settings_FormClosed(object sender, FormClosedEventArgs e) { this.mainForm.ReadIniFile(); } packst du in die Settings Form. Beim erzeugen des Objektes public Form1() { InitializeComponent(); form2 = new Settings(this); ..... } musst du dann die Mainform übergeben. Edit: Eigentlich müsstest du dann auch nur beim Aufruf der Settings-Form diese erzeugen. private void settingsToolStripMenuItem1_Click(object sender, EventArgs e) { new Settings(this).Show(); } Bearbeitet 11. Oktober 20168 j von Panawr
11. Oktober 20168 j Autor @Whiz-zarD Deine 2. Möglichkeit fand ich bis jetzt am Besten, ich hab versucht sie etwas umzuändern und bin soweit das es gerade so aussieht: Settings: public partial class Settings : Form { //string iniText; public Settings() { InitializeComponent(); //Form1 form1 = new Form1(); //iniText = form1.GetIniText(); } //get ini when being called public string iniText { get; } //Method for Form1 public void WriteIniToLabels(string text1, string text2, string text3) { label1.Text = text1; label2.Text = text2; label3.Text = text3; } Form1: public partial class Form1 : Form { //string iniText; string iniPathToPDF; string iniPathToCSV; string iniPathToPCL; string iniPrintPDF; string iniPrinter; string iniPrintserver; string iniText; Settings form2 = new Settings(); public Form1() { InitializeComponent(); try { ReadIniFile(); //create Event for Settings-Close form2.FormClosed += Form2_FormClosed; } } private void Form2_FormClosed(object sender, FormClosedEventArgs e) { ReadIniFile(); } Ich habe denke ich verstanden wie ich meine notwendige Variable iniFile von Form1 and Settings übergebe, aber ich wie schiebe ich sie wieder zurück sobald "Settings" geschlossen wird? Was ich jetzt gemacht habe ist quasi die Hälfte übernommen, allerdings sagt mein Programm das Settings.iniText schreibgeschützt ist? "Für die Eigenschaft oder den Indexer "Settings.iniText" ist eine Zuweisung nicht möglich. Sie sind schreibgeschützt."
11. Oktober 20168 j vor 4 Minuten schrieb Tician: [..] allerdings sagt mein Programm das Settings.iniText schreibgeschützt ist? Das liegt daran, dass du lediglich einen "getter", und keinen "setter" hast. vor 4 Minuten schrieb Tician: public string iniText { get; }
11. Oktober 20168 j vor 6 Minuten schrieb Tician: Ich habe denke ich verstanden wie ich meine notwendige Variable iniFile von Form1 and Settings übergebe, aber ich wie schiebe ich sie wieder zurück sobald "Settings" geschlossen wird? Da würde ich dann auf meine Lösung verweisen, falls du sie noch nicht gelesen hast.
11. Oktober 20168 j Autor Hatte es gemerkt, ich dachte irgendwie an "get" also "kriegt" oder "bekommt" die Variable einen Inhalt, aber es ist genau andersrum... verwirrend.
11. Oktober 20168 j Autor Kann ich nochmal etwas zum Verständnis fragen? Ich dachte immer wenn ich ein Objekt (?) anlege wie zum Beispiel hier Settings form2 = new Settings(); Was passiert dann genau? Ich dachte das ist wie wenn ich eine Variable anlege, quasi eine leere Hülle. Wenn ich also von der Form ein Objekt erstelle dann wird was genau gemacht? Alle Objekte und Variablen angelegt/eingelesen hier zwischen den Klammern stehen? public partial class Settings : Form { }
11. Oktober 20168 j Ich empfehle dir, dir mal ein C#-Buch zu besorgen und die Grundlagen durchzuarbeiten. Für's erste ist vllt. dieser Link ein Einstieg: https://msdn.microsoft.com/de-de/library/ace5hbzh.aspx Was grundsätzlich bei einem "new() ..." passiert, ist, dass alle Felder des Objekts auf ihren Standardwert initialisiert werden (ints auf 0, strings auf null, ...) und der Konstruktor ausgeführt wird. Gegebenenfalls werden vor alledem noch die statischen Felder initialisiert und womöglich vorhandene statische Initialisierer ausgeführt.
Erstelle ein Konto oder melde dich an, um einen Kommentar zu schreiben.