Benutzer mit den meisten Antworten
String in zweite Form in neuem Thread

Frage
-
Hallo,
habe schon so ziemlich jedes Googleergebnis durchgelesen und ausprobiert. Ich versuche eigentlich eine simple Sache; einen String von Form1 zu Form2.
Bei mir sieht das Ganze so aus, dass ich in Form1 den String in eine Textbox eingebe, diese Form dann einen neuen Thread startet, in welchem Form2 dann läuft, Form1 sich beendet und der String in Form2 angezeigt wird.
Einfach nur Loginname, der dann in Form2 angezeigt wird.
Soweit funktioniert das auch, aber nur wenn der String schon über den Designer, also vor dem compilen, in die Textbox eingetragen wurde. Wenn ich das dann manuell machen will, zeigt er mir nur einen leeren String. Irgendwas passt nicht, aber ich komme nicht drauf.
Vielen Dank im Voraus!
Vielleicht noch etwas Code zum besseren Verständnis:
//FORM 1 namespace logtest { public partial class frmLog : Form { public frmLog() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { frmbank frmbank = new frmbank(); frmbank.Show(); } } } //FORM2 namespace logtest { public partial class frmbank : Form { public frmbank() { InitializeComponent(); } private void frmbank_Load(object sender, EventArgs e) { frmLog frmLog = new frmLog(); label1.Text = frmLog.textBox1.Text; } } }
- Bearbeitet xyfz Freitag, 14. Juni 2013 17:44
Antworten
-
Hallo xyfz,
Auch im zweiten Beispiel machst Du den selben Fehler: Du erstellst im OnLoad-Handler von frmBank eine *neue* Instanz (Kopie) der Klasse frmLog. Diese neue Instanz von frmLog hat ganz andere Felderinhalte als die erste!
Eigentlich habe ich dir auf deine Frage schon geantwortet: Du mußt den gewünschten Wert aus frmLog irgendwie an frmBank übergeben. Darum geht's. Du hast zwei Instanzen von zwei Klassen und Du möchtest aus der einen Instanz einen Wert an die andere Instanz übergeben.
Einen möglichen Weg habe ich dir oben gezeigt: Du übergibst txtUser.Text an einen überladenen Konstruktor der Klasse frmBank.
Ein anderer wäre, im Konstruktor von frmBank eine Referenz auf frmLog zu übergeben. Dann könntest Du in frmBank entweder direkt auf das öffentliche Feld txtUser.Text zugreifen, oder den Text über eine in frmLog erstellte Property oder Methode setzen.
Hier einige Lösungswege:
public partial class LogForm : Form { public LogForm() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // 1. Möglichkeit: string-Konstruktor-Argument pushen BankForm bankForm = new BankForm(textBoxUser.Text); // Wenn Polling verwendet werden soll (4./5.): // BankForm bankForm = new BankForm(this); // 2. Möglichkeit: Property-Wert in BankForm pushen bankForm.User = textBoxUser.Text; // 3. Möglichkeit: Methoden-Wert in BankForm pushen bankForm.SetUser(textBoxUser.Text); bankForm.Show(); } // 4. Möglichkeit: Methoden-Polling public string GetUser() { return this.textBoxUser.Text; } // 5. Möglichkeit: Property-Polling public string User { get { return this.textBoxUser.Text; } set { this.textBoxUser.Text = value; } } } public partial class BankForm : Form { private string user; public BankForm(string user) : this() { this.user = user; } public BankForm(LogForm logForm) : this() { this.user = logForm.GetUser(); this.user = logForm.User; } public BankForm() { InitializeComponent(); } public string User { get { return this.user; } set { this.user = value; } } public string SetUser(string user) { this.user = user; } }
Und das sind noch lange nicht alle Möglichkeiten. Man könnte Ereignishandler einsetzen (evtl. zusammen mit INotifyPropertyChanged-Implementation), man könnte die zwei Klassen durch eine Schnittstelle entkoppeln, usw. usf.
Fürs erste - denke ich - hast Du genügend Werte im Lösungsraum stehen.
Gruß
Marcel- Bearbeitet Marcel RomaModerator Freitag, 14. Juni 2013 19:03 Erweitert
- Als Antwort markiert xyfz Freitag, 14. Juni 2013 19:22
Alle Antworten
-
Hallo xyfz,
Im Button-Handler startest Du einen neuen Thread.
Die Ausführung erreicht zunächst ThreadProc wo Du eine neue Instanz von frmBank erzeugst und diese an Application.Run(frmBank) übergibst. Dieser letzte Aufruf erzeugt eine Nachrichtenschleife auf dem neu gestarteten Vordergrundthread und blockiert dort solange bis die Hauptform der Anwendung in diesem Thread (frmBank) geschlossen wird.
Nach dem Abspalten des sekundären Threads im Button-Handler beendest Du aber sofort die aktuelle Applications-Instanz und beim Schließen von Form1 werden auch alle dort enthaltenen Komponenten mit freigegeben, so natürlich auch die TextBox in der Du evtl. deinen Text eingegeben hattest.
Dieser Inhalt ist für immer verloren und wird vom Garbage Collector eingesammelt, da keine Referenzen mehr darauf verweisen. Der erste Thread (eigtl. der Hauptthread der Anwendung) wird beendet, und die Ausführung verläßt Program.Main(). Der einzige Grund, warum frmBank noch zu sehen ist, ist dass eine zweite Application-Instanz auf einem Vordergrundthread erzeugt wurde. Hättest Du myThread.IsBackground = true gesetzt, so wäre auch die Nachrichtenschleife auf dem zweiten Thread mit beendet worden.
Umsonst erzeugst Du dann im neuen Thread eine *neue* Instanz von frmBank. Dort wirst Du den eingegebenen Text natürlich nicht wieder finden (es sei denn die TextBox wurde über den Designer oder im Code auf den gleichen Wert gesetzt).
So weit, so gut. Was tun? - Ganz ehrlich, ich rate dir ab von diesem Design mit Windows Forms auf zwei verschiedenen Threads. Wenn Du willst, erkläre ich dir in aller Ausführlichkeit, was dabei alles schief laufen kann.
Willst Du dieses Design dennoch behalten, dann mußt Du einem überladenen Konstruktor von frmBank den gewünschten Text übergeben, denn für Rückrufe (zugängliche Properties, Funktionen, Felder) aus frmBank nach Form1 wird es zu spät sein:
public static void ThreadProc(object o) { string argument = (string)o; frmBank frmBank = new frmBank(argument); Application.Run(frmBank); } private void button1_Click(object sender, EventArgs e) { System.Threading.Thread myThread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadProc)); myThread.Start(this.txtUser.Text); Application.Exit(); }
Und in der zweiten Form dann:
public frmBank(string user) : this() { this.Text = user; // Kopiert den String! } public frmBank() { InitializeComponent(); }
Viel besser aber, Du sagst uns genauer, was dein Vorhaben ist, und wir sehen uns zusammen nach einer anderen, einfacheren und sichereren Architektur um.
Gruß
Marcel- Bearbeitet Marcel RomaModerator Freitag, 14. Juni 2013 18:15 Erweitert
-
Hallo Marcel,
vielen Dank erst mal für deine ausführliche Antwort. Bin schon am verzweifeln, da ich seit Stunden am probieren bin...
Ich habe mein Code-Beispiel aktualisiert und eine vereinfachte Methode ausprobiert.
Nein, es muss kein weiterer Thread sein. In dem Code-Beispiel habe ich gepostet, wie es in ganz einfacher Form ablaufen kann/soll. Mehr als das will ich auch garnicht.
Ich verstehe nur nicht warum diese simple Methode (Code-Beispiel) nicht funktioniert...
Wenn du mir freundlicherweise noch ein Code-Beispiel geben kannst, wie du das umsetzen würdest, wäre ich sehr verbunden!
-
Hallo xyfz,
Auch im zweiten Beispiel machst Du den selben Fehler: Du erstellst im OnLoad-Handler von frmBank eine *neue* Instanz (Kopie) der Klasse frmLog. Diese neue Instanz von frmLog hat ganz andere Felderinhalte als die erste!
Eigentlich habe ich dir auf deine Frage schon geantwortet: Du mußt den gewünschten Wert aus frmLog irgendwie an frmBank übergeben. Darum geht's. Du hast zwei Instanzen von zwei Klassen und Du möchtest aus der einen Instanz einen Wert an die andere Instanz übergeben.
Einen möglichen Weg habe ich dir oben gezeigt: Du übergibst txtUser.Text an einen überladenen Konstruktor der Klasse frmBank.
Ein anderer wäre, im Konstruktor von frmBank eine Referenz auf frmLog zu übergeben. Dann könntest Du in frmBank entweder direkt auf das öffentliche Feld txtUser.Text zugreifen, oder den Text über eine in frmLog erstellte Property oder Methode setzen.
Hier einige Lösungswege:
public partial class LogForm : Form { public LogForm() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { // 1. Möglichkeit: string-Konstruktor-Argument pushen BankForm bankForm = new BankForm(textBoxUser.Text); // Wenn Polling verwendet werden soll (4./5.): // BankForm bankForm = new BankForm(this); // 2. Möglichkeit: Property-Wert in BankForm pushen bankForm.User = textBoxUser.Text; // 3. Möglichkeit: Methoden-Wert in BankForm pushen bankForm.SetUser(textBoxUser.Text); bankForm.Show(); } // 4. Möglichkeit: Methoden-Polling public string GetUser() { return this.textBoxUser.Text; } // 5. Möglichkeit: Property-Polling public string User { get { return this.textBoxUser.Text; } set { this.textBoxUser.Text = value; } } } public partial class BankForm : Form { private string user; public BankForm(string user) : this() { this.user = user; } public BankForm(LogForm logForm) : this() { this.user = logForm.GetUser(); this.user = logForm.User; } public BankForm() { InitializeComponent(); } public string User { get { return this.user; } set { this.user = value; } } public string SetUser(string user) { this.user = user; } }
Und das sind noch lange nicht alle Möglichkeiten. Man könnte Ereignishandler einsetzen (evtl. zusammen mit INotifyPropertyChanged-Implementation), man könnte die zwei Klassen durch eine Schnittstelle entkoppeln, usw. usf.
Fürs erste - denke ich - hast Du genügend Werte im Lösungsraum stehen.
Gruß
Marcel- Bearbeitet Marcel RomaModerator Freitag, 14. Juni 2013 19:03 Erweitert
- Als Antwort markiert xyfz Freitag, 14. Juni 2013 19:22