Software-Architektur für Anfänger

  • VB.NET
  • .NET (FX) 4.0

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Software-Architektur für Anfänger

    Hallo zusammen,

    ich hätte eine (Anfänger-) Frage zu Software-Architektur im Groben.
    Ich beschreibe zunächst kurz meine Problemstellung:
    In Form1 (eine Art MDI) eine Buttonleiste links, Toolstrip oben und dem Rest der Form ein Panel mit Dock.Fill. In dem Panel wird FormA, B oder C geöffnet (je nachdem welcher Button auf Form1 betätigt wird).
    Nun gibt es in FormB mehrere Label, welche je nach Wert (wird aus einer SPS ausgelesen), die Farben ändern (rot,gelb,grün, wie eine Ampel).

    Nun zur eigentlichen Frage:
    Auf Form1 befindet sich auch so ein Label mit Farbwechsel, sodass, auch wenn FormC oder FormA geöffnet sind, die Zustände im Blick behalten werden können. Einfache Logik: Wenn eins der Label gelb ist, soll das Label auf Form1 auch gelb werden; wenn eins rot ist, soll das Label auf Form1 auch rot werden.

    Wie oder besser wo würde man die "Auswertung" der Werte und die Farbwechsel des Labels programmieren? In FormB wäre es Blödsinn, da man sonst dasselbe noch einmal in Form1 machen müsste...

    Wird soetwas in einem extra Modul "ausgelagert" und dann nur in den entsprechenden Forms aufgerufen?

    Vielleicht noch kurz zum Umfang: es wären ca. 60 Label auf FormB

    RiLo schrieb:

    In FormB wäre es Blödsinn, da man sonst dasselbe noch einmal in Form1 machen müsste...

    Sicher...?
    Ich würde FormB einen Event feuern lassen.
    Form1 fängt diesen und reagiert entsprechend.
    Wieviele Forms werden es denn? Vielleicht biete sich da auch ein Tabcontrol an. Sind die Labels denn alle an die selben Daten gebunden? Also irgendetwas passiert in der Maschine und soll mit der Ampel visualisiert und auf allen Forms angezeigt werden?
    Das würde ich dann fix einbauen und nicht auf jede Form immer wieder.
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Danke euch beiden erst einmal für die schnellen Antworten..

    @Naifu: Ich wäre folgendermaßen an die Sache rangegangen. Auf FormB meine Werte aus der SPS in ein Array packen und dann eine "Ampel"-Sub aufrufen, welche je nach Wert, die entsprechende BackColor für das jeweilige Label ausspuckt.
    Auf Form1 kann ich nun nicht einfach fragen ob eins der 60 Label gelb oder rot ist, da FormB im schlimmsten Fall gerade geschlossen ist. Also müsste ich alles noch einmal (ein bisschen angepasst) schreiben.
    Wie würde das mit dem Event von einer in die andere Form theoretisch funktionieren?

    @Akanel: Es soll nur auf der Hauptform (Form1) im Toolstrip angezeigt werden (ein Label, wechselt einfach nur die BackColor). Wenn der Nutzer nun sieht, dass das Label gelb ist, kann er FormB öffnen und sehen, von welcher der 60 einzelnen Label das Problem kommt. Viel mehr Forms sollen es eigentlich nicht werden, zumindest nicht mit dem "Ampelsystem".
    @RiLo
    Dazu müsstest du mal die geheimnisvolle Sub Ampel posten.
    Oder meinst du prinzipiell wie das mit den Events funzt?

    Aber wenn ich sechzig Labels höre...
    Überdenke dein Konzept, da kann man sicher was zusammen fassen.
    Halte Daten, Verarbeitung und Anzeige immer sauber von einander getrennt.
    Neeneenee. Das MainForm könnte zwar direkt auf die SubForms zugreifen und die Labels auslesen. Aber da sach ich nur: GUI und Daten trennen. Warum werden die SubForm-Labels grüngelbrot? Welche Daten liegen dahinter? Die sollten überprüft oder durchgeackert werden. Und nicht irgendwelche Labels auf Hintergrundfarbe testen. Denn dann kann man ganz einfach coden:

    VB.NET-Quellcode

    1. If Indicators.Any(Function(x) x.IsRed) Then
    2. MainFormLabel.BackColor = Red
    3. Else If Indicators.Any(Function(x) x.IsYellow) Then
    4. MainFormLabel.BackColor = Yellow
    5. Else
    6. MainFormLabel.BackColor = Green
    7. End If


    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    @Naifu: ich meine die prinzipielle Funktionsweise der Events zwischen den Forms. Hinter der Ampel Sub steckt kein Geheimnis. Es wird der aktuelle Wert (aus der SPS), ein vom User einstellbares (Wechsel-)Intervall, ein Grenzwert und das dazugehörige Label übergeben. Dann wird lediglich verglichen ob der aktuelle Wert kleiner als das Intervall-Grenzwert ist, dann wird Label.Backcolor=grün, wenn der wert zwischen Intervall-Grenzwert und Intervall liegt wird es gelb und alles über dem Intervall rot.

    Zusammenfassen lässt sich nicht mehr viel. Es geht um eine relativ große Anlage mit vielen Werkzeugen. Auf der Hauptform (Form1) soll nur schnell für den Bediener ersichtlich sein, ob ein Werkzeug (der 60 vorhandenen) gewechselt werden muss, also wenn das Label bspw gelb ist. Dann würde der Bediener im Optimalfall FormB aufrufen und erkennen können, welches Werkzeug betroffen ist.

    @VaporiZed: Genau das war meine Ausgangsfrage. Also als "Profi" würde man eher die beiden Forms die Anzeige übernehmen lassen und den Code in einem (im Hintergrund agierenden) Modul verstecken? Und dann rufen die Forms (in meinem Fall Form1 und FormB) nur einzelne Subs des Moduls ab, oder?

    RiLo schrieb:

    ich meine die prinzipielle Funktionsweise der Events zwischen den Forms.

    Hmm...

    Form2 mit nem Button drauf.

    VB.NET-Quellcode

    1. ​Public Class Form2
    2. Public Event Form2Event(sender As Object, e As EventArgs)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. RaiseEvent Form2Event(Me, New EventArgs)
    5. End Sub
    6. End Class


    Form1 ohne was drauf.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents _Form2 As New Form2
    3. Private Sub _Form2_Form2Event(sender As Object, e As EventArgs) Handles _Form2.Form2Event
    4. MessageBox.Show("PING")
    5. End Sub
    6. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    7. _Form2.Show(Me)
    8. End Sub
    9. End Class


    Ändert aber nix dran das dein Konzept fragwürdig ist, hatte @'VaporiZed ja schon beschrieben.
    Ich denke ein DataGridView wäre besser als 60+ Labels. Dann müsste man auch nicht eine extra Form öffnen um zu schauen, machste eine Column für die Fehler, lässte noch Zeilen Farbig blinken wenn wo ein Fehler auftritt. Oder machst auch gleich wenn ein Fehler auftritt die Zeile sichtbar(FirstDisplayedScrollingRowIndex setzen). Oder öffnest(doch) ein weiteres Form auch mit DGV, welche dann nur Zeilen mit Fehlern anzeigen. Ich denke so viele Labels und Forms sind komlizierter handzuhaben als ein DataGridView. Nimmt man dazu im Hintergrund ein Dataset, ist es auch recht einfach behobene Fehler zu speichern, wenn Ersatzteile gebraucht wurden kannste das auch eintragen, dauer von Ausfällen, ReparaturZeit, wer war Schuld(rechtlich evtl. fragwürdig), wer hat repariert, und und und. Ich vermute ohne deine Software je gesehen zu haben, eine unvorteilhafte Architektur, schon allein weil ich 60 Labels gelesen hab.

    Aber um dir eine gescheite Architektur vorschlagen zu können, braucht man viel mehr Infos als du uns zur Verfügung gestellt hast.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    RiLo schrieb:

    Also als "Profi" würde man eher die beiden Forms die Anzeige übernehmen lassen und den Code in einem (im Hintergrund agierenden) Modul verstecken?
    Nicht zwangsläufig in einem Modul. Ich würde das so machen, dass Alle Forms dieselbe Datenklasseninstanz an die Hand bekommen. Und wenn eine jene Instanz ändert, bekommen das alle anderen sofort mit. Falls mir niemand zuvorkommt, werd ich heute Nachmittag mal ein Beispielprojekt posten.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ja, so ungefähr sehe ich das auch.
    Also das Thema ist Datenmodellierung, Databinding, Trennung von Gui und Daten.
    Allerdings formübergreifendes Databinding.

    Ich löse das immer mit einem typisierten Dataset, welches ich mittels Partial Classes erweitere.
    Dazu habich einige Infrastruktur, um formübergreifendes Databinding zu gewährleisten.

    So kann ich sowohl die Businesslogic des Datenmodels in partial Classes modularisieren.
    Als auch das Gui modularisieren in Forms, Dialoge, UserControls.

    Alle Gui-"Module" sind gebunden an ein und dasselbe Dataset.
    Und das übergreifende Databinding ist der Mechanismus, mit dem die Forms, Dialoge, UserControls miteinander kommunizieren, wenn nötig.

    Meine Main-Forms tragen üblicherweise ein TabControl mit Tabs der verschiedenen "fachlichen Module" (könnte sein: Stammdaten, Input, Auswertung).
    Auf jedem Tab liegt ein geeignetes UserControl, wo die Fachlichkeit umgesetzt ist.

    Dieses Konzept ist enorm erweiterbar - theoretisch sind zig Fach-Module möglich, ohne dass irgendwelche Files sich auf > 500 Zeilen Code aufblähen.
    Gleichzeitig ist immer ganz klar, welches Problem wo gelöst wird.



    Hmm - vmtl. wirst du meiner Abhandlung nicht folgen können.
    Du redest ausschliesslich von Forms, Panels, ToolstripItems, Label und Kram - an keiner Stelle ist von Daten die Rede.
    Also ich fürchte, für einen Anfänger hast du dir ein Projekt vorgenommen, was eine Architektur erfordert, deren Grundlagen (nämlich Daten, Daten-Objekte, Datenmodellierung) dir völlig fremd sind.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @ErfinderDesRades:
    Ich habe mich tatsächlich nach deinen Tutorials zum typisierten Dataset gerichtet. Ich versuche noch ein bisschen was zur Problematik zu schreiben, ohne dass es zu weit in die Maschinenbau-Richtung geht.
    Die Maschine besteht aus 5 Linien. Jede Linie hat ca. 20 Stationen. An jeder Station gibt es x Werkzeuge, welche, mehr oder weniger regelmäßig, gewechselt werden.
    Ich habe mir also ein Dataset mit 4 Tables erstellt: Strecke, Station, Werkzeug und Wechsel.

    Strecke: ID(PKey), Name
    Station: ID(PKey), Strecke-ID(FKey), Name
    Werkzeug: ID(PKey), Station-ID(FKey), Name, Intervall
    Wechsel: ID(PKey), Werkzeug-ID(FKey), Datum, Standzeit, Bemerkung

    Ich hoffe das ist soweit der richtige Weg.
    Das Problem ist, dass mir dein Tutorial, für das Programmieren gegen das typisierte Dataset, für meine Aufgabenstellung nicht sehr weitergeholfen hat.
    Also habe ich, wahrscheinlich sehr umständlich, für jedes Werkzeug zwei Textboxen, zwei Buttons und eins von meinen ominösen "Ampel-Labels" dazu angelegt.
    In TextBox1 wird der Wert aus der SPS ausgelesen (32Bit-Variable über OPC), der Button dazu löst ein AddWechselRow aus (mit aktuellem Datum und "Zählerstand" aus der Textbox). Diese durchgeführten Wechsel werden in einer anderen Form in einem DataGridView angezeigt (dort können dann auch noch Bemerkungen dazu eingegeben werden).
    In TextBox2 wird das Wechsel-Intervall angezeigt und kann auch durch Eingabe + ButtonClick eingetragen werden (Table Werkzeug/Intervall). Derzeit mache ich das so, dass ich mir die WerkzeugRow per FindID raussuche, mit der dazugehörigen WerkzeugID hart eincodiert (also: blablabla.FindID(25) ). Theoretisch werden keine neuen Werkzeuge hinzugefügt. Deswegen ist das für uns ok. Es gibt bestimmt einen eleganteren Weg, aber den kenne ich (noch) nicht.
    Zur Dataset-Geschichte hätte ich auch noch eine Frage: Gibt es eine Möglichkeit mit Befehlen a la "Select row where Name=xyz" ein offline (XML-) Dataset bzw eine Table davon zu "durchsuchen"?

    Die "Variablen" aus der SPS werden als sogenannte OPC-Items angelegt. Mit Steuerungsname, Adresse, usw...
    Bei diesem Programm greife ich auf 8 unterschiedliche Steuerungen zu. Mir ist noch nichts eingefallen, wie ich das etwas "automatisieren" könnte (eventuell in einen Array schmeißen, um per Schleife alle Werte zu holen?).
    Ich kenne Varianten (>1000 SPS-Objekte), bei denen ein lokaler SQL-Express-Server dazu im Hintergrund läuft und eine DLL die Arbeit übernimmt (Quellcode leider nicht bekannt).

    Ursprünglich wollte ich mir nur "Inspirationen" und Tipps zu Software-Architekturen für Programme solcher Art holen, ohne zu sehr ins Detail zu gehen, aber wahrscheinlich habe ich mich in meinem ersten Post etwas schlecht ausgedrückt.
    Daher als direkte Frage: Hat jemand empfehlenswerte Links zu Artikeln rund um Software-Architektur (bestenfalls in Richtung meines Problems)?

    Und vielen Dank für die Tutorials, ErfinderDesRades. Wirklich sehr gut erklärt, für Einsteiger in die Thematik wie mich.

    @VaporiZed: Danke, ein Beispiel wäre super. Wenn ich deinen Post und den von ErfinderDesRades zusammennehme, weiß ich (glaube ich zumindest) langsam wo die Reise hingeht.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RiLo“ ()

    Jo, das ist ja sehr erfreulich, dass ich mich jetzt bei dir entschuldigen muss, weil ich dein Datenmodellierungs-Verständnis offsichtlich unterschätzt hab!

    Dennoch:

    RiLo schrieb:

    In TextBox1 wird der Wert aus der SPS ausgelesen
    is NoGo.
    Erstens darf es keine Textbox1 geben - gib den Dingen ihren richtigen Namen, sonst kommst du in die Hölle!
    Zweitens: Vor allem soll kein Wert in eine Textbox ausgelesen werden.
    Zum Ein-/aus-lesen ist das Datenmodell da.
    Die Textbox (wenn sie richtig benannt und gebunden ist) wird das dann anzeigen.