Graduierungen BestPractice, oder wie gestalte ich dies am Besten

  • C#

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

    Ich glaub nicht...
    die CollectionViewSource wird hier nur im xaml definiert und an eine Observable Collection gebunden.
    dann kannste da noch gruppieren und sortieren.
    im viewmodel hab ich es noch nicht geschafft eine collectionviewsource zu erstellen.
    "Hier könnte Ihre Werbung stehen..."

    ErfinderDesRades schrieb:

    jo, aber täte mich doch interessieren, was CollectionViewSource in .NetCore macht.

    Nichts. Ist ja auch nicht in .Net Core enthalten. Sucht man im Quellcode vergeblich. In einem WPF Projekt unter .Net Core ist es vorhanden weil dieses Projekt anders erstellt wird. Schaut man sich die unterschiede einer "*.vbproj" oder einer "*.csproj" Datei an sieht man das bei Klassenbibliotheken hier beim SDK folgendes angegeben ist: Microsoft.NET.Sdk wobei bei einem WPF Projekt unter .Net Core folgendes als SDK angegeben wird: Microsoft.NET.Sdk.WindowsDesktop. Hierdurch werden diverse Assemblys mit eingebunden welche in einem normalen .Net Core Projekt nicht zur verfügung stehen.

    MichaHo schrieb:

    im viewmodel hab ich es noch nicht geschafft eine collectionviewsource zu erstellen.

    Es gibt das NuGet Paket: Microsoft.Windows.SDK.Contracts. Hier ist alles hinterlegt was man für die Entwicklung unter Windows benötigt. Aber wie gesagt - "Windows". Also nicht mehr Cross-Plattform.
    Aber Entwickelt man eine reine WPF Anwendung ist das sowieso schnuppe. Denn man muss bedenken das es ja mit dem ICollectionView-Interface nicht getan ist. Man möchte vieleicht eine Notification ins Nachrichtencenter packen oder die Taskbar Optionen (Ladebalken usw.) nutzen. Das sind alles Windows-Spezifische Dinge die in diesem Paket enthalten sind.

    Paket über NuGet holen und mit Hilfe des Imports Windows.UI.Xaml.Data die ICollectionView holen.

    Schöne Grüße
    Sascha

    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,
    ja das hatte ich schon getestet. Mir war nur das Windows.UI.xaml im Viewmodel nicht Recht.
    Ich denke, um Crossplatform abhängig zu bleiben müsste man dann 2 ViewModel Projekte haben (oder mehrer?) 1 für die ViewModels die Crossplatform sind und 1 für ein WPF Projekt.
    Ich kann das mit dem jetzigen Projekt mal testen, denn das soll auf nem Windows Tablet laufen und eventuell auf nem Android Tab.
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    Ich denke, um Crossplatform abhängig zu bleiben müsste man dann 2 ViewModel Projekte haben (oder mehrer?) 1 für die ViewModels die Crossplatform sind und 1 für ein WPF Projekt.

    Ne, keine ICollectionView verwenden.

    Muss ja auch nicht sein, es ist eine erleichterung aber kein muss. Mit Linq kann man alle funktionen der ICollectionView im nu selbst erstellen. Ich habe auch vor kurzem für Xamarin Android eine Filterfunktion ala Telefonbuch erstellt und das einfach mit zwei Collections gemacht.
    Ja, wenn man mal den Luxus gewohnt ist will man ihn auch nutzen, aber wenns nicht geht muss man kreativ werden. ;)

    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 @Nofear23m, @ErfinderDesRades,
    Nachdem ich am WE mit dem Trainer mal über die erste Version der App drüber geschaut habe, gibt es nun die neue Anforderung, das die Graduierungen doch als Liste gespeichert werden sollen, denn er möchte sehen, wenn er eine neue Graduierung vergibt, wann diese vergeben wurde und quasi eine Historie haben.
    OK, kein Problem, mach ich also eine Zwischentabelle denn nun hab ich ja eine m:n Relation. 1 Person kann viele Graduierungen haben und 1 Graduierung kann vielen Personen zugeordnet sein.
    Ich hab dann eine neue Klasse erstellt PersonGraduation:

    C#-Quellcode

    1. public class PersonGraduation : ModelBase
    2. {
    3. public virtual int? PersonId { get; set; }
    4. public virtual Person Person { get; set; }
    5. public virtual int? GraduationId { get; set; }
    6. public virtual Graduation Graduation { get; set; }
    7. public virtual DateTime GraduationDate { get; set; } = DateTime.Today;
    8. }


    Im Context ein entsprechendes DBSet hinzugefügt und dann im OnModelCreationg die Kesy gesetzt:

    C#-Quellcode

    1. public virtual DbSet<PersonGraduation> PersonGraduations { get; set; }
    2. protected override void OnModelCreating(ModelBuilder modelBuilder)
    3. {
    4. modelBuilder.Entity<PersonGraduation>().HasKey(k=> new { k.PersonId, k.GraduationId});
    5. modelBuilder.Entity<PersonGraduation>().HasOne(p => p.Person).WithMany(g => g.Graduations).HasForeignKey(i => i.PersonId);
    6. }

    soweit so gut.
    Lege ich nun eine Person an, wird auch fast alles richtig in die Tabelle geschrieben, die Person ID stimmt, die Graduation Id stimmt und das Datum passt auch....
    ABER... wenn ich nu die Person wieder aus der DB hole (im Provider werden über Include die Graduations mit geladen), dann ist zwar die Graduation Id gefüllt, aber die Graduation ansich ist immer leer.
    Die Person wird allerdings mit geladen... (siehe Bild).

    Ich hab auch schon versucht, in der Graduation Tabelle eine Liste aller Personen zu speichern und beim holen der Graduation die Person ansich mit zu laden, bringt aber auch nichts.
    Ich hab wieder nen Denkfehler und komm nicht drauf.

    Hier noch die beiden Klassen Person und Graduation:
    Person:
    Spoiler anzeigen

    C#-Quellcode

    1. public class Person : ModelBase
    2. {
    3. [Required(AllowEmptyStrings = false, ErrorMessage = "Bitte geben sie einen Vornamen an")]
    4. [MinLength(3)]
    5. [MaxLength(150)]
    6. public virtual string FirstName { get; set; }
    7. [Required(AllowEmptyStrings = false, ErrorMessage = "Bitte geben sie einen Nachnamen an")]
    8. [MinLength(3)]
    9. [MaxLength(150)]
    10. public virtual string LastName { get; set; }
    11. public virtual LoginData AcessData { get; set; }
    12. public virtual string FullName => $"{LastName}, {FirstName}";
    13. public virtual DateTime EntryDate { get; set; } = DateTime.Today;
    14. public virtual GenderEnum Gender { get; set; } = GenderEnum.male;
    15. public virtual PersonTypeEnum PersonType { get; set; } = PersonTypeEnum.Shinzan;
    16. public virtual int MemberId { get; set; }
    17. public ICollection<PersonGraduation> Graduations { get; set; }
    18. public virtual bool IsAdmin { get; set; } = false;
    19. public Person()
    20. {
    21. Graduations = new List<PersonGraduation>();
    22. }
    23. }


    und Graduation:
    Spoiler anzeigen

    C#-Quellcode

    1. public class Graduation : ModelBase
    2. {
    3. /// <summary>
    4. /// der Grad der Graduierung (Schüler = 10 - 1, Meister = 1 - 15)
    5. /// </summary>
    6. public virtual int Degree { get; set; }
    7. /// <summary>
    8. /// Japanischer Name der Graduierung (ergibt sich aus dem entsprechenden Enum)
    9. /// </summary>
    10. public virtual string Description { get; set; }
    11. /// <summary>
    12. /// Enum für die übergeordnete Graduierung (Student oder Master)
    13. /// um später im View zu gruppieren
    14. /// </summary>
    15. public virtual GraduationEnum MemberGraduation { get; set; }
    16. /// <summary>
    17. /// Enum für die Gürtelfarbe (weiß, Rot/Grün, Schwarz)
    18. /// Rot/Grün ab Schüler Grad 9, Rot für Frauen, Grün für Männer
    19. /// Schwarz ab Meistergrad 1
    20. /// </summary>
    21. public virtual BeltColorEnum BeltColor { get; set; }
    22. /// <summary>
    23. /// Enum für die Schriftfarbe, die Schriftfarbe, der Rand und die Hintergurndfarbe beschreiben das Patch
    24. /// auf dem Anzug
    25. /// </summary>
    26. public virtual FontColorEnum FontColor { get; set; }
    27. public virtual BorderColorEnum BorderColor { get; set; }
    28. public virtual BackgroundColorEnum BackgroundColor { get; set; }
    29. /// <summary>
    30. /// Enum für die Farbe der Sterne, Silber, Gold
    31. /// </summary>
    32. public virtual StarColorEnum StarColor { get; set; }
    33. /// <summary>
    34. /// Anzahl der Sterne, abhängig von der Graduierung
    35. /// </summary>
    36. public virtual int StarCount { get; set; }
    37. public override string ToString()
    38. {
    39. return $"{Description} - Grad {Degree}";
    40. }
    41. }


    Eine Abfrage aus dem Provider sieht zum Beispiel so aus:

    C#-Quellcode

    1. public Person Get(int id)
    2. {
    3. return Context.People.Where(p => p.Id == id).Include(l => l.AcessData).Include(g => g.Graduations).FirstOrDefault();
    4. }


    ich komm einfach nicht dahinter, warum mir die eigentliche Graduation nicht mitgeladen wird.

    "Hier könnte Ihre Werbung stehen..."
    Hallo

    Nene, wenn du eine m:n Beziehung haben möchtest hast du zwar schon richtig erkannt das du eine Zwischentabelle benötigst.

    Diese Zwischentabelle enthält lediglich die PersonID sowie die Person-Navigation und die GraduierungsID sowie die Graduierungs-Navigation.
    Für diese Tabelle benötigst du auch kein DBSet.

    Im OnModelCreating hast du schon richtig konfiguriert, allerdings nur in eine Richtung. die zweite Richtung fehlt dir, genau wie das Propertie in der Graduation-Klasse.

    Schau dir mal folgendes an: docs.microsoft.com/en-us/ef/co…2Csimple-key#many-to-many

    Aber ansich stellt sich mir hier die Frage ob dies so richtig gewählt ist. Denn jemand hat ja immer nur eine Graduierung oder?
    Es geht hier vermutlich darum zu wissen welche Graduierung jemand wann hatte oder? Also wie du richtig schreibst eine History. Aber warum dann nicht eine History machen?
    Also eine Tabelle Graduierungshistory als 1:n und dort die Werte reinschreiben. Hier reicht dann die GraduierungsID sowie das Datum wann er diese bekommen hat und bis wann es sie hatte als Nullable-Date.
    Das reicht doch vollkommen oder? Visuell kann sowas ohne Probleme so dargestellt werden wie du es willst.

    Aber... so wie du es im Moment machen willst wäre es Datenhaltungstechnisch ja falsch da so eine Person mehrere Graduierungen gleichzeitig haben könnte was nicht sein darf/kann (denke ich mal).
    Und so hast du schnell mal wenn du nicht aufpasst und das nicht in deinem UserInterface korrekt machst probleme. Ich versuche immer auch mich selbst vor Fehlern zu Schützen und das Datenmodell so zu wählen das solche Fehler erst garnicht pasieren können.

    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. ##

    Arg..... Du hast Recht, daran hab ich mal wieder überhaupt nicht gedacht.

    Klar, ein Mitglied hat immer nur 1 aktuelle Graduierung.
    Gut, dann kann ich aufhören mir die Finger wund zu schreiben.... Ich hol mal mein Backup zurück und starte neu mit der GraduationHistory, die kann ich ja dann wieder an ein ListView oder so binden....

    Danke Dir für den Denkanstoß...
    "Hier könnte Ihre Werbung stehen..."

    MichaHo schrieb:

    die kann ich ja dann wieder an ein ListView oder so binde

    Was das betrifft bist du frei da du ja ViewModels verwendest.

    Da es ne History ist würde ich einfach neben der Graduierung einen 2History" Button machen. Mit Klick auf diesen geht ein Fenster mit der History auf. So musst du auch nicht immer alle Historydaten von der DB holen sondern erst bei Bedarf, also wenn man draufklickt. Sauber, Easy und Performant.

    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. ##