Autor Beitrag
Määx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Fr 08.02.13 16:10 
Hallo zusammen,

ich bin relativ neu in der C#-Welt und habe nun folgendes Problem: in der Main-Methode erzeuge ich in einer globalen Variabel meine Haupt-Form MainApp und rufe sie auf. Weiterhin initialisiere ich in der Main-Methode auch einige SOAP-Services und MSMQ-Messaging. Beim eintreffen einer neuen Nachricht soll nun auf dem TabControl im MainApp erstellt werden. Hierfür habe ich mir eine kleine Methode in der MainApp.cs geschrieben die auch wunderbar funktioniert wenn ich sie durch einen Button-Klick oder ähnlichem aufrufe. Beim Aufruf aus der Programm.cs funktioniert sie leider nicht. Es ist, als ob sich die Referenz auf meine MainApp ändern würde oderso... kan mir jmd. einen Tipp geben, woran es liegen könnte?
Hier noch der wichtigste Code:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
static class Program
    {
        static MainApp mainApp;

        static void Main()
        {
            Application.ApplicationExit += new EventHandler(OnApplicationExit);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            [...]

            mainApp = new MainApp();
            mainApp.addNewTab("Test");

            Application.Run( mainApp );
        }

        public static void newMessage(String msg)
        {
            mainApp.addNewTab(msg);
        }
    }


Vielen Dank schonmal für eure Hilfe!

Edit:
ich habe mein mainApp.addNewTab jetzt in try/catch gesetzt und es kommt tatsächlich folgende Fehlermeldung:
Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement tabControlMsgs erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.

bin aber absolut ratlos, wie ich das beheben kann...


Zuletzt bearbeitet von Määx am Di 12.02.13 15:39, insgesamt 1-mal bearbeitet
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: Fr 08.02.13 16:55 
Wird denn die newMessage Methode von einem Event der besagten SOAP bzw. MSMQ Services asynchron aufgerufen? Wenn ja solltest du mal chechen ob das nicht eine andere Thread ist als der zu dem deine Form gehört und du in Crossthreading Probleme läufst.
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Di 12.02.13 15:04 
Hey,

erstmal vielen Dank für deine Hilfe und entschuldige meine späte Rückmeldung - über Karneval hatte ich meine Anfrage ganz vergessen :)
Das mit dem threading könnte tatsächlich der Fehler sein.
Ich habe eine Klasse erstellt, die die MSMQ-Funktionalität übernimmt:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
[...]
string msmq_name =  ConfigurationManager.AppSettings["MSMQ_NAME"];
if (!MessageQueue.Exists(msmq_name))
    MessageQueue.Create(msmq_name);
MessageQueue receiveQueue = new MessageQueue(msmq_name );
receiveQueue.MulticastAddress = ConfigurationManager.AppSettings["MSMQ_MC_ADDR"];
receiveQueue.BeginReceive();
receiveQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(processRequestNewMsg);
[...]


In der processRequestNewMsg wird die Nachricht dann aufgeschlüsselt und per EventHandler an die Program.cs übergeben (die problematisch newMessage() wird dort aufgerufen). Ich selber starte keinen Thread, das MSMQ.BeginReceive() wird aber sicherlich als Thread arbeiten... aber da ich diese Funktionalitäten ja nicht manipulieren kann, habe ich keine Ahnung wie ich jetzt aus der newMessage-Methode auf meine GUI zugreifen kann?

Kannst du mir hierbei weiter helfen?

Vielen Dank
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: Di 12.02.13 15:43 
Wenn es ein CrossThread Call ist solltest du da eigentlich eine Exception bekommen. Wenn da keine kommt solltest du auf jedenfall mal dein Exceptionhandling prüfen ob du da nicht ein paar Lücken hast.

Um die Form zu ändern bedarfs es eines synchronisierten Aufrufs. Dazu stellen dir die Controls in Winforms die Invoke Methode zur Verfügung. In deinem Fall könnte das so Aussehen

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
public static void newMessage(String msg)
{
    if(mainApp.InvokeRequired)
        mainApp.Invoke((MethodInvoker)(() => newMessage(mainApp, msg)));
    else            
        mainApp.addNewTab(msg);
}

Für diesen Beitrag haben gedankt: Määx
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Di 12.02.13 16:32 
Hey,

super, das ganze klappt! Habe dafür allerdings noch eine weitere Methode erstellen müssen und habe, damit man den Code nicht doppelt schreiben muss den else-Zweig angepasst:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
public static void newMessage(String msg)
{
    if(mainApp.InvokeRequired)
        mainApp.Invoke((MethodInvoker)(() => newMessage(mainApp, msg)));
    else            
        newMessage(mainApp, msg);
}  
public static void newMessage(MainApp mp, String msg){
    mp.addNewTab(msg);
}


Ist das so korrekt oder mache ich das zu kompliziert?

Aber schonmal vielen vielen Dank - wäre ich ohne deine Hilfe nie drauf gekommen!
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: Di 12.02.13 17:25 
Zitat:
Habe dafür allerdings noch eine weitere Methode erstellen müssen und habe, damit man den Code nicht doppelt schreiben muss den else-Zweig angepasst:


Häh? Was müßte man da doppelt schreiben?
Määx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 123



BeitragVerfasst: Di 12.02.13 17:36 
Hey,

sorry, das war aus meinem gekürzten Code so nicht ersichtlich. Bei Ankunft einer neuen Nachricht mache ich mehr als den einen Aufruf addNewTab. Den hattest du entsprechend in deinem Beispiel ja direkt in die else-Verzweigung gelegt. Ich rufe hier wie beim invoke dann die Methode auf. Das meinte ich mit "doppelt schreiben".

Viele Grüße und vielen Dank für die schnelle & kompetente Hilfe!
Määx