# C# Statusanzeige



## Oest (17 Mai 2019)

Hallo,

ich habe gerade ein C# Verständnissproblem: 

  //----------------------------------------------------------------------
        // Zyklisch laufend

   private void Btn_start_zykl_Click(object sender, RoutedEventArgs e)
        {

            // Create a timer with a  ms interval.
            aTimer = new System.Timers.Timer(2000);
            // Hook up the Elapsed event for the timer. 
            aTimer.Elapsed += OnTimedEvent;
            aTimer.AutoReset = true;
            aTimer.Enabled = true;

            status.Background = new SolidColorBrush(Colors.Green);                                  ->>> funktioniert

        }

        private void Btn_stop_zykl_Click(object sender, RoutedEventArgs e)
        {
             aTimer.Stop();
            status.Background = new SolidColorBrush(Colors.Red);                          ->>> funktioniert
        }

        private void Ablauf()
        {

          ;

                  // Kommunikationsablauf (entfernt für Test)


        }
        // 
        private void OnTimedEvent(Object source, ElapsedEventArgs e)
        {
            if (!client.Connected)
            {
                 aTimer.Stop();                                                                              ->>> funktioniert -> stoppt den Zyklus
                 MessageBox.Show("Pleace Connect PLC");                                   ->>> funktioniert -> meldet genau einmal - das die PLC nicht erreichbar

                 status.Background = new SolidColorBrush(Colors.Red);                ->>> funktioniert  # NICHT #       Wieso???
                // anhalten Zyklus bei Komm Verlust
            }
            else
            {
                Ablauf();
            }
        }//Ende Zyklus
        //----------------------------------------------------------------------


Ja, wenn das jemand erklären kann, wäre schon interessant.
Vielen Dank!

Das ganze soll einfach in grün und rot den aktuellen Status darstellen.


----------



## Larry Laffer (17 Mai 2019)

Ich hätte dazu einige Anmerkungen :
- Ich hätte die Methode statt an Timer.elapsed an Timer.Tick gehängt - das ist aber sicher nicht der Fehler
- in deiner OnTimerEvent-Methode stoppst du den Timer ohne ihn wieder zu starten - somit wird diese Methode nicht wieder aufgerufen. Frage dazu : warum stoppst du den Timer wenn du doch eine zyklische Anzeige benötigst ?
- der Aufruf einer MessageBox übernimmt die Resourcen des UI solange diese geöffnet ist. Faktisch ist das im Grunde eine neue Form. Besser wäre, wenn du z.B. ein Label oder eine TextBox sichtbar oder unsichtbar schaltest. Das blockiert dann nicht das UI ...

Gruß
Larry


----------



## Oest (20 Mai 2019)

Hallo,

der Timer soll einen zyklischen Ablauf simulieren. Quasi wenn oben btn  start click -> zyklus läuft ...  btn stop click -> zyklus stop
In diesem Ablauf, dort wo 
                  // Kommunikationsablauf (entfernt für Test) steht,  läuft normalerweise die Kommunikation mit der SPS  und das  Datenspeichern in CSV.

Das funktioniert auch erstmal soweit.
Mir ist nur aufgefallen, dass in den zwei "btn click" Methoden dieser  "Farbwechsel" super klappt. In der OnTimedEvent Methode aber nicht mehr.
Frage mich einfach, wie das C# "denkt".
Das es nicht zyklisch wie eine SPS läuft ist mir schon klar. Allerdings  hätte ich erwartet, das die Befehle in dem OnTimedEvent auch nach dem  aTimer.Stop(); alle noch einmal abgearbeitet werden, da das Programm ja  schon "innerhalb" der methode ist.




> - der Aufruf einer MessageBox übernimmt die Resourcen des UI  solange  diese geöffnet ist. Faktisch ist das im Grunde eine neue Form.  Besser  wäre, wenn du z.B. ein Label oder eine TextBox sichtbar oder  unsichtbar  schaltest. Das blockiert dann nicht das UI ...


Heisst das, dass Programm wartet an dieser Stelle, solannge MessageBox nicht quitiert ist?
Wie geht das mit dem sichtbar/unsichtbar?

Vielen Dank


----------



## M-Ott (20 Mai 2019)

Oest schrieb:


> Wie geht das mit dem sichtbar/unsichtbar?


Das ist die Eigenschaft Visible. Die musst Du für die jeweilige Control auf false oder true setzen.


----------



## Oest (20 Mai 2019)

Hallo,

der Timer soll einen zyklischen Ablauf simulieren. Quasi wenn oben btn  start click -> zyklus läuft ...  btn stop click -> zyklus stop
In diesem Ablauf, dort wo 
                  // Kommunikationsablauf (entfernt für Test) steht,  läuft normalerweise die Kommunikation mit der SPS  und das  Datenspeichern in CSV.

Das funktioniert auch erstmal soweit.
Mir ist nur aufgefallen, dass in den zwei "btn click" Methoden dieser  "Farbwechsel" super klappt. In der OnTimedEvent Methode aber nicht mehr.
Frage mich einfach, wie das C# "denkt".
Das es nicht zyklisch wie eine SPS läuft ist mir schon klar. Allerdings  hätte ich erwartet, das die Befehle in dem OnTimedEvent auch nach dem  aTimer.Stop(); alle noch einmal abgearbeitet werden, da das Programm ja  schon "innerhalb" der methode ist.




> - der Aufruf einer MessageBox übernimmt die Resourcen des UI  solange  diese geöffnet ist. Faktisch ist das im Grunde eine neue Form.  Besser  wäre, wenn du z.B. ein Label oder eine TextBox sichtbar oder  unsichtbar  schaltest. Das blockiert dann nicht das UI ...


Heisst das, dass Programm wartet an dieser Stelle, solannge MessageBox nicht quitiert ist?
Wie geht das mit dem sichtbar/unsichtbar?

Vielen Dank


----------



## Heinileini (20 Mai 2019)

Oest schrieb:


> Frage mich einfach, wie das C# "denkt".
> Das es nicht zyklisch wie eine SPS läuft ist mir schon klar. Allerdings  hätte ich erwartet, das die Befehle in dem OnTimedEvent auch nach dem  aTimer.Stop(); alle noch einmal abgearbeitet werden, da das Programm ja  schon "innerhalb" der methode ist.


Frage mich einfach, wie Du denkst.
Was hast Du denn in die Methode hinein programmiert, die beim Auftreten eines OnTimedEvents aufgerufen wird? Was hast Du dafür vorgesehen, dass "alle noch einmal abgearbeitet werden", bevor sich die Methode wieder schlafen legt?

Gruss, Heinileini


----------



## Larry Laffer (20 Mai 2019)

Du mußt bei so etwas berücksichtigen, dass ein Timer eine Komponente des Systems ist wie auch ein Button oder Label oder oder ...
Ich hatte deine Aufgabe jetzt so verstanden :
- Button_Start startet die zyklische Abfrage und Darstellung - hier wird der Timer gestartet, der im 2 Sekunden-Intervall abläuft
- Button_Stop hält das Ganze wieder an
- im zyklischen Durchlauf wird abhängig vom Ergebnis die Meldung ausgegeben oder nicht (oder ein Farbwechsel gemacht ... oder oder).

Was im Grunde schon nicht schön ist (ich kenne da aber nicht die Folgen) dass du mit jedem neuen Button_Start dem Eventhandler des Timers die Methode wieder erneut zuweist. Das solltest du auch nicht tun. Dies gehört in den Konstruktor deiner Form.
Probier mal den Timer.Tick für deine Methode zu nehmen und den Timer nicht zu stoppen.
Probier außerden NICHT mit einer MessageBox zu arbeiten - nach Messagebox.Show wird in der aufrufenden Methode erst dann weiter gearbeitet wenn die Messagebox wieder beendet wird - sondern mit dem Visible eines Labels.

C# bzw. .Net denkt nicht - es hat seine Spielregeln - und diese sind eigentlich noch nicht mal besonders schlimm (finde ich).
Konntest du mit dem, was ich geschrieben habe, etwas anfangen ? Wenn nicht dann frag bitte nach ...

Gruß
Larry


----------



## Oest (21 Mai 2019)

Hallo Larry,

vielen Dank erstmal.

Ich habe schon einige Tutorials und Uni Skripte durchgearbeitet, und versuche eben die "Spielregeln" des C# zu durchschauen.
Anscheinend fehlen mir zur Strukturierung des C# mit WinForms Programmes noch Informationen.
Leider sind die meisten Übungsbeispiele innerhalb einer Klasse, und die jetzt auftretenden Fehler kamen dort rein aus Programmaufbau Gründen nicht vor.

Gibt es vielleicht einen "Programmaufbau Style Guide" für kleine WPF Anwendungen, oder so etwas?


----------



## Larry Laffer (21 Mai 2019)

@Oest:
Ganz grundsätzlich kann ich dir die Foren CodeProject und StackOverFlow empfehlen - mein Favorit ist das erstgenannte.
Ich gebe dir Recht, dass es am Anfang unter Umständen schwierig ist, die vielen Fragestellungen zu kanalisieren und zu verstehen - du darfst aber gerne fragen - speziell hier kann ich dir schon das eine oder andere dazu sagen ...
Für die Zukunft mußt du dich entscheiden, ob du Forms oder WPF machen willst - das ist nämlich ein "kleiner" Unbterschied ... ich persönlich hatte mich für Forms entschieden (obwohl angeblich totgesagt) und bis heute noch nichts gefunden, was ich damit nicht hinbekommen hätte ...

Aber einmal prinzipiell gefragt :  wieviele Kenntnisse in dem Thema hast du denn schon ?
Und :  was möchtest du machen / erreichen ...?

Gruß
Larry


----------



## Oest (21 Mai 2019)

@Larry

Das Ziel ist ein Grundprogramm zur Kommunikation mit der SPS.
Momentan zum Schreiben in eine CSV. Dabei soll im C# ein polling laufen, was alle x ms auf einen DB schaut, ob ein Start von der SPS kommt. Wenn ja -> append CSV ;wenn nein -> weiter kreisen

Funktioniert jetzt auch. Der Haken war wohl, dass man innerhalb eines neuen Tasks/Threads oder was immer via # Dispatcher.Invoke(() => tbx_msg.Text = "idle");# nach "aussen" senden muss

Ich habe Erfahrung mit AWL, SCL und ein paar Robotersprachen.  
Ziel ist, c# soweit zu beherrschen, das man sichern in csv, evtl sql und speichern/rücklesen einer Config PLC<>PC hinbekommt.
Kann doch nicht so schwer sein. ;-p


----------



## Heinileini (21 Mai 2019)

Oest schrieb:


> Funktioniert jetzt auch.


Das klingt so, als würde es jetzt funktionieren. Aber



> Kann doch nicht so schwer sein. ;-p


klingt viel weniger überzeugt!?


----------



## Larry Laffer (21 Mai 2019)

Oest schrieb:


> Funktioniert jetzt auch. Der Haken war wohl, dass man innerhalb eines neuen Tasks/Threads oder was immer via # Dispatcher.Invoke(() => tbx_msg.Text = "idle");# nach "aussen" senden muss



Wenn du einen Task oder Thread hast und Dinge an die Controls des UI übergeben möchtest dann mußt du die Controls "invoken" - das heißt, dass du dem Control im Grunde etwas in einen Übergabebereich legst und das das Control (oder die Componente) damit arbeitet wenn das UI wieder die Kontrolle hat - also z.B. wenn in deinem Task oder Thread oder Backgroundworker irgendwo ein Sleep o.ä. steht.
Die genannten Funktionalitäten laufen quasi neben dem eigentlichen System her und quasi unabhängig von ihm.

Du hast mir aber in deinem Code mitgeteilt, dass du mit einem Timer arbeitest - das ist eine Componente des UI und läuft mit ihm und nicht nebenher. Hier kannst du mit den Controls etc. direkt arbeiten. Allerdings hatte ich dir ja auch schon anfangs geschrieben, dass eine Messagebox dabei wieder eine Ausnahme ist, da diese die Abarbeitung bis zu derem Schließen in sich selbst übernimmt. Deshalb hatte ich dir ja auch von der Verwendung davon abgeraten und dazu geraten, mit der Sichtbarkeit der "normalen" Controls zu arbeiten.

Bedenke immer :  eine .Net-Anwendung wird eben (im Unterschied zu einem SPS-Programm) NICHT zyklisch abgearbeitet ...

Gruß
Larry


----------



## Oest (22 Mai 2019)

Hallo,

ich habe das ganze, getreu dem Motte: Es wird solange geändert, bis es geht, nochmal stark umgebaut.
Message Boxen raus, Timer Zyklus durch Task ersetzt, Meldungen per diesem Invoke übergeben

Der Aufbau in dem Task zum pollen arbeitet ja wieder zyklisch...und jetzt mit einer Art StateMachine wodurch die Komm mit der SPS als Handshake funktioniert.

Ziel war ja, das innere des Task unabhängig vom UI zu haben, damit das bedienbar bleibt, aber trotzdem Nachrichten zu übermitteln. 

Mit dem Aufbau bin ich jetzt erstmal zufrieden. Jetzt wird das ganze eben erweitert, und einfach mal geschaut, was man damit so alles anstellen kann. (Sql, Backup/Restore usw.)

Danke für die Hilfe Larry!


----------



## Larry Laffer (22 Mai 2019)

Na ... wenn du schon einen Task sinnvoll an den Start bekommen hast und die Controls des UI, mit denen du darin zusammenarbeitest, vernünftig invoked bekommst dann bist du auf der .Net-Schiene aber schon ein ganzes Stück vorwärts gekommen ...


----------

