Laden...

Fensterinhalt wird weiss

14 Antworten
2,834 Aufrufe
Letzter Beitrag: vor 17 Jahren
Fensterinhalt wird weiss

Hallo,

Folgendes Problem:
Ich habe ein Form in diesem ist ein Knopf zum öffnen einer SAP Verbindung mit GUI. Das SAP-Fenster wird, so weit ich das sehe modal geöffnet. Nun ist aber der Inhalt des erstens Fensters (das mit dem öffnen-Knopf) nicht mehr lesbar, da der komplette Client-Bereich weiss ist. Herumschieben kann man das Form aber noch.

Erst wenn das modale Fenster geschlossen wird, kann man wieder was sehen.

Ich bin mir jetzt nicht sicher, ob das ein "generelles" Problem ist, im Zusammenhang mit modalen Fenstern, oder ob es sich um eine Eigenschaft von ERPConnect.NET handelt, welches ich verwende um den SAP GUI zu öffnen und die Verbindung zum SAP R3 herzustellen.

Hat jemand von euch sowas schonmal gesehen? Und viel interessanter... eine Lösung dafür? 🙂

Gruss, Shi

Build something that's idiot proof, and they'll build a better idiot

Hallo Shihan,

Ich vermute mal, dass das hier das Problem sein wird: [FAQ] Warum blockiert mein GUI? - der SAP-Aufbau wird vermutlich im GUI-Thread ausgeführt und deswegen wird die nicht mehr aktualisiert.

Gruß,
Neko

ja, daran habe ich auch schon gedacht, jedoch würde das auslagern des SAP GUI Threads in einen eigenen Thread doch gegen diesen Tipp verstossen:

Nur ein GUI-Thread

Alle Fenster sollten/müssen immer aus dem GUI-Thread erzeugt werden. Das Erzeugen von Fenster und Controls sollte nicht/nie in extra Thread verlagert werden. Wenn man das tut, kann das - so paradox das klingt - ebenfalls zum Blockieren des neue erzeugten Fensters und zu anderen Problemen führen.

Ausserdem:
Ich muss in meiner Anwendung warten, bis der SAP-GUI wieder geschlossen wird, erst dann kann ich mit anderen Verarbeitungen weiterfahren. Wenn ich also einen anderen Thread machen würde, dann würde mein 1. Thread ja fröhlich weiterrasseln und der User könnte daran weiter rummanipulieren (an Controls, etc.), was nicht gewünscht ist.

Build something that's idiot proof, and they'll build a better idiot

hast du beim aufruf den owner mitgegeben?

also, ich muss jetzt sagen, dass ich nicht weiss ob das Fenster nun modal geöffnet wird oder nicht, ich weiss nur das der Aufrufende Prozess unterbrochen wird, bis das geöffnete Fenster wieder geschlossen wird. Aber man kann das öffnende Fenster hin und herschieben.. das verwirrt mich etwas, dachte das gehe nicht, wenn ein anderes Fenster modal geöffnet ist.

Zu deiner Frage: also ich öffne den GUI nicht selber. Also ich verwende ++nicht ++so etwas:

GuiForm guiForm = new GuiForm();
guiForm.ShowDialog(this);

Sondern, das ERPConnect-Framework kapselt das intern. Ich rufe das z.B. so auf:

        private void OpenGui()
        {
            Transaction trans = new Transaction(r3con);

            trans.TCode = "FB03";

            try
            {
                r3con.Open();
                trans.Execute();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.Source);
            }
            finally
            {
                r3con.Close();
            }
        }

Via trans.Execute wird der GUI dann geöffnet, zuerst muss aber via r3con.Open eine Verbindung aufgebaut werden.

Build something that's idiot proof, and they'll build a better idiot

in dem fall ist es sehr wahrscheinlich, das der aufruf den aufrufenden thread blockiert.

am besten du setzt vor dem aufruf deine gui auf enabled = false und machst den aufruf in einem thread. und nach dem schließen des threads setzt du deine gui wieder auf enabled = true

ich verstehe leider nicht ganz wie du das meinst.

Du meinst ich soll generell das ganze Form sperren? Z.B.:

Form1.Enabled = false;

Und der Aufruf also im selben Thread oder in einem anderen? Der User muss einfach in der Lage sein das aurufende Fenster noch zu sehen. Weil er gewisse Daten übernehmen muss, falls der automatische Transfer nicht klappt (wenn das SAP unbehandelte Fehler meldet).

Aber evtl. wende ich mich mal am besten an den Hersteller. Vielleicht kennt der ja nen Trick.

Build something that's idiot proof, and they'll build a better idiot

Du meinst ich soll generell das ganze Form sperren?

ja

Und der Aufruf also im selben Thread oder in einem anderen?

für den aufruf erstellst du einen thread.

Ok, da ich einige andere Problem-Brocken nun in der Anwendung lösen konnte, komme ich schliesslich wieder auf diese Problematik zurück.

Ich habe aber noch eine Frage bezüglich der Art, wie der neue Thread erstellt wird. Soll ich einen "normalen" Thread benutzen, z.B.:


    Thread t = new Thread (new ThreadStart (SapExecutionMethod));
}

Oder, würde sich ein BackGroundWorker in diesem Fall besser eignen? Da er noch gerade ein paar schöne Events anbietet, mit welchem ich auf Ereignisse reagieren kann?

Bisher ist es wie folgt:
-> User clickt im Form auf Button "OK" -> Wenn Daten OK sind, wird eine Methode aufgerufen: "FiRechnungBuchen()" -> Diese Methode (welche im Form ist) ruft die SapVerarbeitungsMethode auf, welche ausgelagert ist (die Methode, welche das blockieren verursacht). Im weiteren beinhaltet diese Methode (die in der Form) im Moment die Fehlerbehandlung (try/catch) sowie eine Ausgabe ob die Aktion erfolgreich durchgeführt wurde oder nicht (mit MessageBox). Wenn Ok, dann wird eine weitere Methode aufgerufen, welche dann die Rechnung entsprechend in einen anderen Status weiterleitet -> nächste Rechnung wird angezeigt, ansonsten bleibt der Dialog stehen.

Im wesentlichen bekomme ich von der SapExecuteMethode (ich nenn sie mal, die Blockier-Methode) einige Rückgabewerte. Einerseits true/false, ob generell die Aktion durchgeführt wurde. Dann aber auch eine Liste mit Rückgabewerten (~Strings). Mit diesen Informationen kann ich dann in der Methode im Form entscheiden, ob ein Fehler aufgetreten ist oder nicht. Zusätzlich kann aber natürlich auch noch eine Exception auftreten, welche im Form behandelt wird.

Sehe ich das richtig, dass wenn ich mit dem BackgroundWorker arbeitet (vermutlich auch sonst mit dem extra Thread), dass ich dann eine Art Rückgabe-Objekt erstellen müsste, welches mir die benötigten Informationen sammelt:

public class SapReturnInfos
{
    private bool operationSuccess;
    private List<ReturnMessages> returns;
    private Exception ex;
    
    ...
}

Ich hoffe ich habe euch nicht zu sehr verwirrt. Ich würde einfach gerne wissen wie ihr das anpacken würdet um das Problem sauber zu lösen.

Gruss, Shi

Build something that's idiot proof, and they'll build a better idiot

Hi,

ich würde das Ganze in einen Backgroundworker auslagern.
Siehe: http://www.galileocomputing.de/openbook/visual_csharp/visual_csharp_19_015.htm

Wenn der User nun auf OK klickt, dann startest du den BGworker.
Mit diesem gibst du gegebenfallst noch einen Progress zurück.
Und am Ende wird von dem auch noch ein Event ausgelöst, in dem du dann dein Objekt mitgeben kannst.
That's it....

mfg
michlG

Hallo TheShihan,

ob du einen Thread oder BackgroundWorker nimmst, kannst du dir aussuchen. Was dir lieber ist.

Wenn du nur die drei Informationen


    private bool operationSuccess;
    private List<ReturnMessages> returns;
    private Exception ex;

hast, brauchst du kein extra Objekt, weil für alle drei Informationen passende Properties in RunWorkerCompletedEventArgs gibt.

herbivore

ja ich denke dann ist der Fall klar was ich nehme. Danke.

Build something that's idiot proof, and they'll build a better idiot

Und wenn das öffnen des Fenster im GUI Thread ist und nur die Hintergrundaktion in einem anderen, vielleicht geht es dann ja. Allein das Fenster öffnen muss ja nicht in einen eigenen Thread.

nein, es ist schon so.

Das ganze ist wie folgt aufgebaut:

                    // configure and build the batch input
                    trans.TCode = "FBV0";
                    // SAPMF05V
                    trans.AddStepSetNewDynpro("SAPMF05V", "0100");
                    trans.AddStepSetCursor("RF05V-BELNR");
                    trans.AddStepSetField("RF05V-BUKRS", companyCode);
                    //... etc. etc.

                    R3Connection r3con = new R3Connection(...);
                    r3con.UseGui = true; // or false for background processing

                    // set connection
                    trans.Connection = r3con;

                    // excecution mode
                    trans.ExecutionMode = TransactionDialogMode.ShowOnlyErrors;

                    // execute transaction
                    trans.Execute();

Das GUI poppt also auf, der Prozess wird "angehalten" bis die Verarbeitung im GUI durchgelaufen ist, da der User das GUI auch beinflussen kann und veränderung an der Buchung vornehmen kann.

Erst nach dem Ausführen von "Execute()" wird das Programm weiter ausgeführt. Execute -> führt GUI aufruf intern auf, macht aber auch die Verarbeitung.

Build something that's idiot proof, and they'll build a better idiot