MVVM OpenSource Communityprojekt - HomeStorage

  • WPF

Es gibt 94 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

    MVVM OpenSource Communityprojekt - HomeStorage

    Hallo Leute

    Der User @MichaHo hat den wunsch geäußert mit MVVM anzufangen, was ich unterstützen möchte. Meine Tutorialreihe ist allerdings noch nicht so weit und das wird auch noch eine Weile dauern.
    Jetzt gab es zwei möglichkeiten, ich greife ihm ausserhalb dieses Forums unter die Arme oder innerhalb des Forums. Da ich helfen möchte den WPF Bereich des Forums zu beleben war meine entscheidung klar was ich mache.

    Deshalb erstelle ich nun diesen Thread. Dieser soll NICHT dazu dienen über MVVM zu diskutieren und auch nicht die Vorteile und/oder Nachteile eines Patterns erleutern.

    Wofür ist dieser Thread:
    Hier möchte ich die Einzelnen Schritte welche am Projekt vollzogen werden immer erläutern. Also wenn ich eine änderung am Projekt mache werde ich hier mittels passender Überschrift darauf aufmerksam machen und die änderungen erklären.
    Anschliessend kann jeder Fragen zu diesen änderungen stellen oder verbesserungen einbringen.
    Das Projekt selbst wird auch GitHub gehostet und dort auch verwaltet.

    Wofür ist dieser Thread NICHT:
    Zum diskutieren über MVVM oder andere Pattern.
    Aber auch nicht um Bugs welche sich evtl. eingeschlichen haben oder wenn jemand eine Funktion im Program wünscht, hierfür gibt es auf GitHub die Issues, bitte diese auch zu verwenden.

    Um was geht es in diesem Projekt:
    Ein korrektes (!!) MVVM Beispiel aufzuzeigen (ohne dem einsatz von MVVM Frameworks wie MVVM Light, Prism oder ähnlichem) und zu zeigen das man mit MVVM alle Teile des Code wiederverwenden und austauschen kann. Die Struktur soll so aufgebaut werden das die Layer so gut wie möglich von einander getrennt sind und die Applikation später umgebaut werden kann. Beispielsweise soll man später eine UWP App machen können welche dieselben Daten der Datenbank verwendet. Dies würde erfordern der DataAccessLayer getauscht wird da auch EF Core nicht direkt von einer UWP aus auf eine außenliegende DB zugreifen kann, dies soll mit dem geringsten Aufwand möglich sein weshalb die Layer so weit wie möglich runtergebrochen werden.

    Gewisse Hauptfunktionen sollte die Applikation können damit diese ein vollständiges Programm darstellt da ich der Meinung bin das es keinen Sinn macht ein MVVM Beispiel zu erstellen welches zwar korrekt aufgebaut ist jedoch völlig sinnfrei ist. Alle implementierten Funktionen müssen Funktionieren und einen Sinn ergeben und nicht einfach wieder ein MVVM Beispiel abgeben welches im Grunde für nichts da ist und keinen Sinn ergibt. Davon gibt es bereits genug im Netz.

    Geplante Funktionen des Programms:
    Schnell und einfach zu bedienen, einfache Ersteinrichtung und der Schwerpunkt auf Usability.

    Grundfunktionen:

    *Verwaltung von Lagern, Sublagern, Lagerplätze
    *Artikelverwaltung verschiedender Typen mit Lagerplatzzurodnung
    *Attributverwaltung für Artikel (Ablaufdatum, Abmessung, Farbe usw.)
    *Schnittstellen für Artikelverwaltung als Pluginsystem (z.b. Barcodeabruf über API)
    *Notificationsystem (unterschreiten von Mindestlagermänge, Ablaufdatum usw)
    *Listengenerierung (Einkaufsliste, Obsoletliste)
    *Scanfunktion im Pluginsystem (Barcodescanner, NFC Scanner, QR Code Scanner)
    *Reportingfunktionen (Übersichten, Einkaufszettel, History)

    Unterstützte Endgeräte:

    *Desktop WPF

    Jeder ist eingeladen das Projekt zu Forken und dieses aktiv zu unterstützen. Ich werde es absichtlich nicht ZU schnell vorantreiben damit auch jeder "mitkommt" der sich für MVVM interessiert und wir auch Zeit haben Fragen bez. Änderungen hier zu beantworten.
    Wie schon oben erwähnt, verwendet auch die Issues damit dieser Thread nicht zugemüllt wird.



    Alle weiteren Details findet Ihr im angehängten (vorläufigen) Lastenheft.

    Hier das GitHub Projekt
    Dateien
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Nofear23m“ ()

    WTF
    Du machst Dir ja richtig Arbeit. Fettes Danke dafür. :thumbup:
    Auch wenn ich noch die vorherigen Tutorials abarbeite, werde ich diesen Teil hier verfolgen und mit Sicherheit auch einiges aus der vorgelebten Praxis mitnehmen.
    :thumbup: :thumbup: :thumbup:
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.

    Erstes Commit - Projektstruktur

    Erste vorläufige Projektstruktur erstellt

    Soeben habe ich auf Git Syncronisiert und die Projektstruktur erstellt. Diese ist vorläufig und zeigt mal wie eine Solution in VisualStudio für MVVM aufgebaut wird. Wichtig hier das die Projektmappen getrennt sind.

    Ein Diagram zeigt auch welches Projekt einen Verweis auf welches hat. So sieht man z.b. schöne das die Views das Model nicht kennen und das Model aber auf nicht die View. Das ViewModel weis auch nichts vom View aber umgekehrt.
    Anbei auch ein Screenshot welcher die Projektstruktur in VS zeigt.

    Wichtig ist mir immer das die Projekte völlig getrennt von einander sind. So ist sichergestellt das die einzelnen Projekte wiederverwendet werden können.

    Auflistung der Projekte:

    Model - wird die Plain-POCO Klassen beinhalten (.NET Standard damit wiederverwendbar z.b. in einer UWP App)
    ViewModel - wird unser dreh und Angelpunkt zwischen View und Logik (.NET Standard damit wiederverwendbar z.b. in einer UWP App)
    View - Hier kommen unsere UserControls für die Desktop-Appliketion rein (.Net Framework 4.6.2)
    HomeStorage.App - Unsere App welche im grunde startet aber ihr werden sehen das diese nicht viel machen wird. (.Net Framework 4.6.2)

    VieModel.Tests - Unser Projekt wo die UnitTests für das ViewModel reinkommen - Ja wir werden auch Testen, eines der Vorteile von MVVM (.Net Framework 4.6.2)

    Das wars mal fürs erste...stay tuned

    Grüße
    Sascha
    Bilder
    • Dependencies Graph_HomeStorage.png

      31,96 kB, 1.028×879, 188 mal angesehen
    • SolutionExplorer_HomeStorage.PNG

      9,69 kB, 327×234, 231 mal angesehen
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Aktueller Commit - Model Basisklassen und Interfaces

    Sooo liebe Leute, wieder ein Commit

    Ich habe mal mit den ersten Modelklassen begonnen.
    Anbei auch ein Diagram das man es versteht.

    Es gibt 3 Interfaces. ILogcalDelete, ILogicalTimestamp und IProtocolable
    Hintergrund hierbei ist das bei alle Klassen welche Beispielsweise ILogicalDelete implementieren die Logik für Loschmarkierungen automatisch übernommen wird. Da bei Datenbanksystemen (meiner Meinung nach) so gut wie nie gelöscht werden soll (ausser durch z.b. einen Admin direkt am SQL Server), soll hier der Entwickler vor sich selbst geschützt werden. Wird als ein Objekt gelöscht soll später automatisch dafür gesorgt werden das der Vorgang Rückgägnig gemacht wird und stattdessen der Datensatz "nur" als gelöscht markiert wird.

    Das selbe gilt für ILogicalTimestamp. Hier soll automatisch eingetragen werden wann ein Datensatz erstellt oder zuletzt geändert wurde.

    Jedes Object welches IProtocolable implementiert soll Protokollierbar sein.
    Die Basisklasse ModelBase sollte glaube ich klar sein.

    Die Basisklasse ConcurrencyModelBase erbt selbst von ModelBase wobei hier noch die Eigenschaft RowVersion hinzukommt.
    Diese ist dafür da das wir eine Konflikterkennung haben. Jedes Objekt welches von dieser Basisklasse erbt besitzt also eine integrierte Konflikterkennung.
    Wir werden später dann sehen das hier EntityFramework automatisch sobald wir einen Datensatz aktualisieren nicht nur die ID innerhalb des "WHERE" mitgibt sondern auch die RowVersion.
    Das bedeutet aber auch, das es keinen Datensatz zum aktualisieren findet wenn die RowVersion in der DB nicht mehr gleich der lokalen ist und quittiert uns dies mit einer ConcurrencyException.

    Ansonsten ist das Model noch nicht so weit.

    Nun eine Frage an die Community damit ihr auch mitarbeiten könnt:

    Bringt doch Vorschläge bez. der implementierung von Lagern, SubLagern. Wie würdet Ihr das modellieren?
    Jeder Artikel soll einem Lager und einem Lagerort zugeordnet werden können. Wobei es aber auch Sublager geben können sollte. Also im Lager Garage soll es die Sublager Wandschrank und Hängeschrank geben können.

    Los gehts!

    Grüße
    Sascha
    Bilder
    • Model.png

      96,97 kB, 1.651×818, 234 mal angesehen
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hi,
    beim durchschauen des Projektes stellen sich mir paar Fragen:
    1. Was genau tut die Klasse ConcurrencyModelBase ?
    2. Warum ist ArticleAttribute und Attribute 2 Klassen? Hätte doch auch 1 gereicht, oder?
    3. Model Validator und ModelValidation ??? Müsstes Du erklären...
    "Hier könnte Ihre Werbung stehen..."
    Hallo NoFear ,
    was muss ich bei GitHub denn genau runterladen.
    Hab mich eben registriet weil ich auch mitmachen will.
    Finde die Idee Super :thumbup:

    Edit: Ich muss es Clonen. Werde mich mit GitHub auseinder setzten müssen.
    Jedenfalls , ich bin dabei.

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

    MichaHo schrieb:

    1. Was genau tut die Klasse ConcurrencyModelBase ?

    Reicht dir das in Post #5 nicht?

    MichaHo schrieb:

    2. Warum ist ArticleAttribute und Attribute 2 Klassen? Hätte doch auch 1 gereicht, oder?

    Wie man ganz gut am Diagram sehen kann ein Artikel X Attribute vom Typ ArticleAttribute haben. Ein ArticleAttribute kat wiederum ein Attribute Property vom Typ Attribute und ein Value Property vom Typ String. Weil....
    Es kann ja mehrere Attributtypen geben. Gewicht, Farbe, Länge, Höhe, Haltbarkeitsdatum. Diese Attribute werden denn Verknüpft mit dem ArticleAttribute.
    Man kann dann später wählen welches Attribut ein Artikel besitzt und den Wert dazu eingeben. Damit diese aber nicht direkt im ArticleAttribut gesetzt werden mit z.b. einem String (weil da kann man sich ja vertippen und dann gibt es MHD und MDH vieleicht), so kann man dann auch später selektieren nach allen Artikeln mit einem gewissen Attribut und einem Wert. Hoffe das war einigermaßen verständlich.

    MichaHo schrieb:

    3. Model Validator und ModelValidation ??? Müsstes Du erklären...

    OK, wir haben in den Modelklassen Annotierung verwendet. <Required> oder <MinLength(3)>. Das bedeutet das in diese Eigenschaft mindestens 3 Zeichen eingegeben werden muss und nicht NULL sein darf.
    So wird EF Core dann später auch die DB Tabellen anlegen. Halten wir uns dann nicht daran bekommen wir einen Fehler vom DB System zurück. Aber später z.b. im ViewModel möchten wir eine einfache möglichkeit haben zu prüfen ob ein Model-Objekt korrekt (also Valid) ist. Dafür habe ich ein paar Methode geschaffen.

    ModelValidation.Validate - Prüft die übergebene Modelklasse (welche von ModelBase erben muss) und übergibt eine leere Liste wenn alles OK oder die Validierungsfehler wenn nicht alle in Ordnung wie z.b. ("Das Feld 'Title' ist ein Pflichtfeld")
    In ModelBase gibt es die Methode Validate welche ValidateEntity im ModelValidator aufruft welche wiederum einfach die oben genannte ModelValidation.Validate aufruft.
    Ich habe diese Methoden einfach nur getrennt weil wir später vieleicht ja Logging, Debugausgaben oder andere Logik implementieren. Wer weis.

    Amro schrieb:

    Hab mich eben registriet weil ich auch mitmachen will.
    Finde die Idee Super

    Das freut mich!

    Amro schrieb:

    Edit: Ich muss es Clonen. Werde mich mit GitHub auseinder setzten müssen.
    Jedenfalls , ich bin dabei.

    Wenn du "mitwirken" willst musst du es "Forken". Und diesen "Fork" musst du dann Clonen da du sonst keine PullRequests machen kannst.

    Wenn ihr fragen habt, nur her damit.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    HI,
    Sorry, Post 5 komplett verdrängt....
    ich schau mir morgen die Klassen noch einmal an... ich meine die Models würden von ModelBase erben und nicht von Concurrency, kann mich aber irren, deswegen guck ich morgen noch mal nach.
    Die Interfaces und nun auch die Concurrency sind soweit klar.
    Das mit den Validation ist mir nun auch klar, wobei ich das bei EF6 glaub anders gemacht hatte... muss ich nochmal gucken...

    Edit: nochmal kurz ein Wort zu den Lagern.... ich würde es nicht aufblasen wollen... ein Lager und max 1 Lagerplatz, sollte für eine Hausverwaltung bezüglich Lebensmittel & Co. doch reichen, oder wie seht ihr das? Lager=Abstellraum, Lagerplatz=RegalLinks, Lagerplatz=RegalRechts
    "Hier könnte Ihre Werbung stehen..."
    Hallo

    MichaHo schrieb:

    ich meine die Models würden von ModelBase erben und nicht von Concurrency

    Schau dir mal das Diagram nochmal an, da sieht man es ja gut.
    Die Modelklasse erben schon von ModelBase. Aber Artikel erbt von ConcurrencyBase. Und ConcurrencyBase erbt von ModelBase. Also hat Artikel alles was ModelBase hat UND die eine Eigenschaft aus ConcurrencyBase noch dazu damit sichergestellt ist das wir bei Article auch brav eine Konflikterkennung haben da dies eine wichtige Tabelle ist.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Gut, dann belassen wir es einfach bei Lager ohne Sublagern und Lageplätzen.
    Also gibt es für einen Artikel einfach Lager = Lager 1 und Lagerplatz = "xyz" hier kann dann z.b. auch C12-13-10 für spezial-Lagerflächen drinnen stehen, halten wir es einfach.

    Aber, die nächste Frage an die Community damit Ihr was zu nachdenken habt:
    Erstellen die Struktur um z.b. das Mindesthaltbarkeitsdatum für Artikel erfassen zu können. :?:

    Beispiel: Wir haben 12 Packungen Reis. 3 davon laufen in drei Wochen ab, 9 Packungen aber erst in 4 Monaten.
    Wir können es also nicht im Artikel selbst hinterlegen oder in den Attributen, was nun?

    Und los gehts!!

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    ich nur vs2013, daher kannich nicht richtig mitspielen.
    Aber ich find das Diagramm aus post#5 sehr unübersichtlich finde, mit seiner Durchsetzung von Klassenhierarchie und relationalem Modell. Daher habich mal einen Auszug des relationalen Modells gemacht, wie ich vermeine, es dem Diagram ablesen zu können:

    Vlt. finds der eine oder annere so ja auch übersichtlicher.
    (Und hofflich ists ühaupt richtig)

    Ach - noch nebenbei Frage: Ich lese im Diagram: "Attributes als ICollection(Of ...)" - ist das wirklich so, dass dort auch VB-Schlüsselworte auf deutsch übersetzt sind?

    ErfinderDesRades schrieb:

    ch - noch nebenbei Frage: Ich lese im Diagram: "Attributes als ICollection(Of ...)" - ist das wirklich so, dass dort auch VB-Schlüsselworte auf deutsch übersetzt sind?

    Ja, in der Deutschen Version schon. Ich weis nicht genau aber ich erinnere mich dunkel zu glauben das man das auch abschalten kann. Stört mich aber nicht.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Sehe ich genauso. Gerade für die V1 (evtl. kann es sich dann später jeder selbst erweitern oder wir gemeinsam) sollte man alles so einfach wie möglich halten.
    Klar, was nötig ist muss rein, alles was nicht unbedingt nötig ist bleibt erstmal weg.

    Beibt nur noch die von mir gestelte Frage:
    Erstellen die Struktur um z.b. das Mindesthaltbarkeitsdatum für Artikel erfassen zu können.

    Beispiel: Wir haben 12 Packungen Reis. 3 davon laufen in drei Wochen ab, 9 Packungen aber erst in 4 Monaten.

    Wir können es also nicht im Artikel selbst hinterlegen oder in den Attributen, was nun?

    Wenn keine eine Idee hat für einen Lösungsansatz löse ich auf indem ich es heute Abend mal implementiere wie ich mir das denke.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Hallo Leute,
    hab jetzt das Projekt in Visual Studio.
    Ich hab aber einige Probleme.
    Das ViewModel ZielFramework in Projekteigenschaften ist leer.
    Was soll ich da eintragen?
    Im Projektmappenexplorer ist bei den Abhängikeiten ein gelbes Ausrufezeichen.
    Hat es mit dem Framework zu tun?
    Das selbe gilt für Model?
    Was mach ich da falsch bei Klonen/Foken?
    Hallo

    Welches VS hast du denn?
    Das Model und das ViewModel sind .Net Standard Bibliotheken damit falls es mal notwendig wird, diese weiterverwendet werden können.
    .NET Standard 2.0 ist also voraussetzung.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##