Generelle Programmstruktur



  • Hallo, ich bräuchte mal ein paar Tipps, wie man eine komplexe Anwendung gescheit strukturiert. Klar, da gibt es das MVVM-Pattern, dazu habe ich auch schon einiges gelesen, aber wirklich verstanden habe ich es nicht. Mir geht es auch erstmal nur darum das ganze Programm in verschiedene Klassen zu separieren, damit ich besser den Überblick behalten kann. Bisher hatte ich nämlich alles in die Window Klasse reingeschrieben.

    Vielleicht ein paar Infos zu meinem Programm. Im Prinzip ein normales Paint/CAD-Programm. D.h. ich speichere die visuellen Objekte wie Linien, Ellipsen usw. in einer VisualCollection die Teil meiner MyCanvas-Klasse ist. Die MyCanvas-Klasse ist dabei von der Canvas-Klasse abgeleitet.
    Weiter habe ich eine abstrakte Basisklasse ToolBase auf der die einzelnen Tools wie ToolLine, ToolEllipse usw. aufbauen.

    Das Problem das sich jetzt abzeichnet, ist z.B. der Zugriff aud die verschiedenen Elemente der Benutzeroberfläche.
    Hier habe ich z.B. eine Klasse "LineExpanderView" (von Expander abgeleitet) die Textboxen usw. enthält, um die Daten wie Start- und Endpunkt der ausgewählten Linie anzuzeigen. Die einzige Möglichkeit die ich sehe ist z.B. über den Konstruktor das UIElement an die Klasse zu übergeben. Gibt es eine andere Möglichkeit wie man erreichen kann, dass von jeder Klasse auf die Benutzeroberfläche zugegriffen werden kann?
    Ein weiteres Problem ist die abstracte ToolBase-Klasse. Diese beinhaltet zum Beispiel die OnMouseDown-Funktion, wodurch z.b. eine neue Linie erzeugt wird. Jetzt müsste ich um die Liniendaten in dem Expander darstellen zu können diesen als Argument der OnMouseDown-Funktion übergeben. Allerdings ist diese Funktion ja nun abstract, ich bräuchte also eine abstracte Basisklasse des Expanders, die es wohl nicht gibt. Denn je nachdem welches Tool gerade ausgewählt wurde kann der OnMouseDown-Funktion ja auch ein RectangleLineExpanderView übergeben werden. Ich hoffe es wird verständlich was ich meine ;).

    Und noch ein Problem. Die ganzen visuellen Objecte sind von der Klasse DrawingVisual abgeleitet. D.h. es sind keine PropertyChangedEvents wie bei der Klasse INotifyPropertyChanged möglich. Gibt es trotzdem eine Möglichkeit die Daten der z.B. Linien an ihren LineExpander zu binden? Sind hier evtl. DependencyProperties nützlich? Im Moment übergebe ich einfach das erzeugte visuelle Object an die LineExpanderView-Klasse und leite die einzelnen Werte "per Hand" an die Textboxen weiter, was sicherlich nicht sehr elegant ist.

    Vielleicht kann mir einfach mal jemand grob skizzieren, wie man den Aufbau der Anwendung gestalten könnte.

    Gruß Student83



  • dass von jeder Klasse auf die Benutzeroberfläche zugegriffen werden kann?

    Also das halte ich für eher weniger gut. Du solltest ne Trennung schaffen, es gibt Models, Views und ViewModels oder anstatt der ViewModels, eben nen Controller. Die Models(in dem Falle deine Entitäten) sollte eigentlich nichts von der Existenz einer GUI wissen. Dann gibts die Views(deine Gui) und den Controller, der ist dafür zuständig um aus den Models und der View das zu bauen was du brauchst. Vermutlich wäre es hier sinnvoll interfaces anzubieten die diese Funktionalität bereitstellen, und dann konkrete Klassen implementieren diese Interfaces.
    Eventuell reicht dir das ja schon an Informationen.



  • EDIT:
    Vielleicht mal ein Beispiel:

    In der Window Klasse habe ich die Variable LineWidth. Diese kann über die GUI verändert werden. Jetzt soll auf dem Canvas Linien mit der eingestellten LineWidth gezeichnet werden. Wie kann ich nun die Canvas-Klasse wissen lassen, wann die LineWidth verändert wurde. Das Canvas ist dabei kein direktes Child des Windows und befindet sich (in weitere Elemente verschachtelt) in einem TabItem. Es kann natürlich auch mehrere TabItems und damit mehrere Canvases geben.

    Wenn ich MVVM richtig verstehe würde man die Variable nicht im Window, sondern in einer Model-Klasse anlegen, die dann wiederum Member der ViewModel-Klasse des Windows ist. Das ViewModel würde dann an den DataContext des Window gebunden. Nur das bringt mich bei meinem Problem auch nicht weiter.

    Wenn ich noch mit C++ programmieren würde, würde ich die Variable einfach global deklarieren, was ja mit C# nicht mehr sinnvoll ist und auch gar nicht mehr geht.



  • push



  • Ich habe mich jetzt eines Tricks bedient. Wenn ich z.B. eine Collection in der MainWindow-Klasse als "static" deklariere:

    static ObservableCollection<Object> m_ObjectsCollection;
    

    kann ich über:

    MyProgram.MainWindow.ObjectsCollection[0].Draw(drawingContext);
    

    von jeder beliebigen Klasse aus zugreifen. Ist diese Vorgehensweise zu empfehlen?



  • Static sollte nur in ausnahmenfällen verwendet werden....



  • Und warum? Schlechtere Performance, unsicher oder mehr genutzter Speicher?

    Und wie sonst kann ich die Kommunikation zwischen zwei Klassen (Beispiel oben) laufen lassen.



  • Du könntest die Kommunikation über Events laufen lassen, oder einem Controller den du dazwischen schaltest.



  • Was ist den ein Cotroller? Wie würde dieser aussehen?
    Zu den Events. Wie würde ich das machen? Mal angenommen ich erzeuge zur Laufzeit ein UserControl und möchte jetzt im Statusbar den Text "Wird geladen" anzeigen. Ich habe aber keine Referenz zu der TextBox im Statusbar.
    Es kann doch nicht sein, dass man nur aus der Window-Klasse auf die GUI zugreifen kann.



  • Student83 schrieb:

    Wenn ich noch mit C++ programmieren würde, würde ich die Variable einfach global deklarieren, was ja mit C# nicht mehr sinnvoll ist und auch gar nicht mehr geht.

    Das ist in C++ auch nicht gut.

    Wird oft aus Faulheit gemacht.

    Propertys!?


Anmelden zum Antworten