Autor Beitrag
funcry
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: Do 19.03.09 00:06 
Die Lösung die ich derzeit gefunden habe erscheint mir wie ein übler hack, daher die Frage ob es nicht anders besser gelöst werden könnte.

Innerhalb eines Threads erzeuge ich eine Form. Da ich jedoch GUI Aufrufe invoken muss mache ich das. Nur die innerhalb des Invvoke-Blocks erzeugte Form ist ausserhalb nicht sichtbar. Deshalb muss ich zuerst innerhalb des Threads jedoch ausserhalb des Invokes die Form erzeugen, und danach innerhalb des Invokes erneut. Andernfalls bleibt die Form leer obwohl dort Steuererlemente untergebracht sind. Zudem muss ich die Form ausserhalb des Invokes erzeugen damit ich später darauf zugreifen kann.
Funktionieren tut das. Der Code sieht so aus:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Thread mythread = new Thread(new ThreadStart(delegate
            {
                foreach (UI_CSV_Detail myui_csv_detail in this.Fui_csv_master.Flist_ui_csv_detail)
                {
                    if (myui_csv_detail.cb_select.Checked)
                    {
                        // Erzeugen der Form:
                        UI_Stats_Master myui_knn_stats_master = new UI_Stats_Master();
                        Invoke(new MethodInvoker(delegate
                        {
                            // hier nochmal:
                            myui_stats_master = new UI_Stats_Master();
                            myui_stats_master.MdiParent = this.MdiParent;
                            myui_stats_master.Show();
                        }));


Ein Workaround wäre die Form ausserhalb des Threads zu erzeugen und in einer List zu packen. Aber gibt es auch eine Lösung wie ich die Form innerhalb des Threads erzeugen kann ?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 19.03.09 01:00 
Damit eine Form funktioniert braucht sie ein Message Pump in dem Thread zu dem sie gehört.
Die startet man (übrigens genauso wie im Hauptthread) mit Application.Run.

Also solltest du dein Form wie folgt anzeigen.

ausblenden C#-Quelltext
1:
2:
UI_Stats_Master form = new UI_Stats_Master();
Application.Run(form);


Das als MDIChild ein Form aus einem anderen Thread als der MDIParent herhalten kann bezweifle ich aber. Das sollte dir mit CrossThread Call Exceptions um die Ohren fliegen.

Dein gezeigter Code funktioniert(oder eher nicht) weil deine erzeugte Form gar nicht in dem erzeugten Thread myThread läuft. Du erzeugst ja die Form im MethodInvoker Delegaten der wenn ich deinen Codeausschnitt richtig interpretiere im Hauptthread läuft. Somit gehört myui_stats_master auch zum Hauptthread.
funcry Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: Do 19.03.09 15:25 
Danke für die Erklärung!

Das war mir so nicht bewusst - insbesondere auch dass ich dies innerhalb eines Threads tun kann.

Allerdings gibt es noch ein Problem. Der Aufruf von Application.Run() blockiert den aufrufenden Thread so lange bis die erzeugte Form geschlossen wird. Die Anwendung erstellt also die Form wie gewünscht, wartet aber dann bis ich die Form schliesse. In meinem Fall dient die Form nur zur Darstellung von Diagrammen. Der Ablauf des Programmes sollte also in mythread fortgeführt werden.


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
private void b_asd_Click(object sender, EventArgs e)
        {
            Thread mythread = new Thread(new ThreadStart(delegate
            {
                foreach (UI_CSV_Detail myui_csv_detail in this.Fui_csv_master.Flist_ui_csv_detail)
                {
                    if (myui_csv_detail.cb_select.Checked)
                    {
                        UI_Stats_Master myui_stats_master = new UI_Stats_Master();
                        Application.Run(myui_stats_master);

                        /*Invoke(new MethodInvoker(delegate
                        {
                            myui_stats_master = new UI_Stats_Master();
                            myui_stats_master.MdiParent = this.MdiParent;
                            myui_stats_master.l_symbol.Text = myui_csv_detail.Fmaster_csv_helper.symbol_name;
                            myui_stats_master.Show();
                        }));*/

                        
                        string symbol_name = myui_csv_detail.Fmaster_csv_helper.symbol_name;
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 19.03.09 16:03 
Run brauchst du eigentlich nur für die Main-Form. Abgesehen vom unnötigen äußeren new-Aufruf war dein erster Code eigentlich so richtig.
user profile iconfuncry hat folgendes geschrieben Zum zitierten Posting springen:
Zudem muss ich die Form ausserhalb des Invokes erzeugen damit ich später darauf zugreifen kann.
Wenn es unbedingt nötig ist:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
                        UI_Stats_Master myui_knn_stats_master = null;
                        Invoke(new MethodInvoker(delegate
                        {
                            // hier nochmal:
                            myui_stats_master = new UI_Stats_Master();
                            myui_stats_master.MdiParent = this.MdiParent;
                            myui_stats_master.Show();
                        }));
Damit kannst du die Closure-Variable erzwingen.
Aber mir würde so eine Verwurstelung von Nebenthread und Form Kopfschmerzen bereiten, dir anscheinend auch schon ;) . Du solltest den Thread unbedingt von der Form abkoppeln und stattdessen mit Events/... arbeiten.

_________________
>λ=
funcry Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 110
Erhaltene Danke: 1

Win7 64, XP 32
C# (VS 2010 EE), Delphi (TD 2006 Win32)
BeitragVerfasst: Do 19.03.09 16:35 
Danke für die Hilfe. Die Initialisierung der UIs mit null funktioniert.

Danke auch für den Hinweis mit Events. Wenn ich darüber nachdenke, sollte sich der inzwischen immer unübersichtlichere Code damit eleganter gestalten lassen :-)