Einzigartigen Schlüssel generieren

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von kafffee.

    Einzigartigen Schlüssel generieren

    Hallo liebe Community.

    Ich habe eine Playlist LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist, die Instanzen einer Klasse beinhaltet und in einem DataGrid angezeigt wird. Diese Instanzen der Klasse haben eine Eigenschaft TrackListID As Integer.

    Diese Eigenschaft soll dynamisch vergeben werden, so dass jeder Eintrag einen einzigartigen Schlüssel hat, damit , wenn ich z.B. einen Eintrag aus der Playlist entfernt wird, kein Schlüssel doppelt vergeben wird, wenn ich erneut Einträge hinzufüge. Dazu habe ich folgende Funktion geschrieben:

    VB.NET-Quellcode

    1. Private Function HoleHoechsteTrackID(TrackListe As ObservableCollection(Of ViewModel.MP3FileInfoVM)) As Integer
    2. Dim HoechsteID As Integer = 0
    3. For Each Eintrag In TrackListe
    4. If Eintrag.TrackListID > HoechsteID Then
    5. HoechsteID = Eintrag.TrackListID
    6. End If
    7. Next
    8. Return HoechsteID
    9. End Function


    Aufgrufen wird das Ganze so:

    VB.NET-Quellcode

    1. Private Sub AlbumZuPlaylistZufuegen_Execute(obj As Object)
    2. Dim Objekt As ViewModel.MP3FileInfoVM = CType(obj, ViewModel.MP3FileInfoVM)
    3. Dim DateiListe As New List(Of ViewModel.MP3FileInfoVM)
    4. Dim ListeZumHinzufuegen As New ObservableCollection(Of ViewModel.MP3FileInfoVM)
    5. For Each item In MainModule.InhaltGesamt
    6. If item.Album = Objekt.Album Then
    7. DateiListe.Add(item)
    8. End If
    9. Next
    10. If Deck2IstSelektiert = False Then
    11. Dim StartID = HoleHoechsteTrackID(LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist) + 1
    12. For Each AudioDatei In DateiListe
    13. AudioDatei.TrackListID = StartID
    14. StartID = StartID + 1
    15. ListeZumHinzufuegen.Add(AudioDatei)
    16. Next
    17. End If
    18. [...]


    Beim ersten Hinzugügen von Einträgen zur Playlist funktioniert das auch, aber bei jedem weiteren Mal wird manchmal, aber auch nur manchmal, von HoleHoechsteTrackID ein scheinbar zufälliger Wert ausgegeben...

    Hat jemand vielleicht eine Ahnung warum oder hat vielleicht eine alternative Idee?

    Gruss,

    kafffee

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

    Auch wenn es nix mit der Frage zu tun hat: Die ganze HoleHoechsteTrackID-Funktion kannst Du Dir dank LINQ schenken:

    VB.NET-Quellcode

    1. Dim StartID = LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Max(Function(x) x.TrackListID) + 1

    Und so nebenbeier: If Deck2IstSelektiert = False Then -> If Not Deck2IstSelektiert Then; StartID = StartID + 1 -> StartID += 1

    Eine ForEach ist toll, aber manchmal sollte man doch eine For-Schleife nehmen:

    VB.NET-Quellcode

    1. For i = 0 To DateiListe.Count - 1
    2. DateiListe(i).TrackListID = StartID + i
    3. ListeZumHinzufuegen.Add(DateiListe(i))
    4. Next

    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.
    Ich habe eine statische Variable für so etwas. Jedes mal wenn ein Titel zur Playlist hinzugefügt wird, rufe ich diese Funktion auf und habe so eine einzigartige Id. Ich mache das statisch, weil ich von verschiedenen Stellen aus zur Playlist hinzufügen kann, aber nur eine Playlist habe. So spart man sich die sucherei nach der höchsten Id. Kannst du nur in einem ViewModel zur Playlist hinzufügen und es gibt keine mehrfach Instanzen davon, kann man das auch nicht-statisch machen. Aber sobald mehrere Instanzen im Spiel sind, kann auch mal was statisches sinnvoll sein.

    VB.NET-Quellcode

    1. Private Shared nextPlaylistItemId As UInteger = 0
    2. Public Shared Function GetNextPlaylistItemId() As UInteger
    3. nextPlaylistItemId += 1
    4. Return nextPlaylistItemId
    5. End Function

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

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

    Nachdem die LINQ-Version auch nicht funktionierte, habe ich den Fehler gefunden, als ich schon gar nicht mehr danach suchte. Ich hatte an einer Stelle im Code DeckLeft mit DeckRight verwechselt. Das erklärt auch die scheinbar zufälligen Rückgabewerte.

    Naja super jedenfalls danke für die schnellen Antworten und Tipps.

    Jetzt hab ich aber ein anderes Problem, und zwar, wenn derselbe Track zweimal geaddet wird, dann bekommt er eine ID, die aber nicht einzigartig ist. Was natürlich so nicht gewollt ist. Und zwar sagen wir ich adde Track1, dann Track2, dann wieder Track1. Mit genau dem gleichen Aufruf derselben Methode AlbumZuPlaylistZufuegen_Execute. Dann bekommt bei mir de erste Track die 1 zugewiesen, der zweite die 2. Wenn ich dann aber Track1 nochmal zufüge, dann bekommt der erste Eintrag die 3 und der dritte Eintrag in der Playlist auch die 3, also quasi rückwirkend wird der erste Eintrag nochmal verändert von 1 auf 3.

    Was mir auch aufgefallen ist, dass dann Track1 und Track3 beide selektiert sind in meinem DataGrid, obwohl ich SelectionMode="Single" eingestellt hab...Und weiters: Mein Objekt sollte in der Eigenschaft .TrackListID theroretisch immer eine 0 drin haben. Hat es aber nicht, sondern wieder eine scheint es zufällige Zahl. Als Objekt wird per CommandParameter einfach nur der Datensatz einer selektierten Items aus einer Listbox, die die Alben anzeigt, übergeben. Es scheint mir so, als würden die automatisch durchnummeriert. Das wäre an sich nicht weiter schlimm, weil ich ja die .TrackListID ja sowieso auf StartID setze, aber vielleicht ist es wichtig...

    Hier mein Code, der Einfachheit halber die Funktion, um nicht Alben, sondern Tracks zuzufügen. Bei beiden aber dasselbe Problem, also wenn man dieselben Tracks mehrfach addet.

    VB.NET-Quellcode

    1. Private Sub MusiktitelZuPlaylistZufuegen_Execute(obj As Object)
    2. Dim Objekt As ViewModel.MP3FileInfoVM = CType(obj, ViewModel.MP3FileInfoVM)
    3. 'Objekt.TrackListID = 0
    4. Dim StartID As Integer = 1
    5. If Not Deck2IstSelektiert Then
    6. If LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Count > 0 Then
    7. StartID = LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Max(Function(x) x.TrackListID) + 1
    8. End If
    9. Objekt.TrackListID = StartID
    10. LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Add(Objekt)
    11. Else
    12. If LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Count > 0 Then
    13. StartID = LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Max(Function(x) x.TrackListID) + 1
    14. End If
    15. Objekt.TrackListID = StartID
    16. LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Add(Objekt)
    17. End If
    18. End Sub


    Hier mal noch das DataGrid:

    XML-Quellcode

    1. <DataGrid ItemsSource="{Binding Playlist, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" CanUserResizeRows="False" IsReadOnly="True" HeadersVisibility="Column" SelectionMode="Single" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto" SelectedIndex="{Binding PlaylistGewaehlterIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" vm:VisualHelper.EnableRowsMove="True" ToolTip="{Binding PlaylistToolTip, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
    2. [...]
    3. </DataGrid>


    @DTF
    Du machst also auch einen Musikplayer? Baust du auch auf die bass.dll auf? Wenn du Fragen hast gerne stellen, vielleicht kann ich dir zur Abwechslung auch mal unter die Arme greifen...
    @kafffee Wie wäre es mit Guid.NewGuid()? Die Dinger sind einzigartig.
    learn.microsoft.com/de-de/dotn…guid.newguid?view=net-6.0
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    An sich eine gute Idee, aber es ist wie ich es vermutet habe:

    Auch dieser Schlüssel wird, wenn ich den gleichen Musiktitel adde, doppelt in meiner Playlist angezeigt....

    Also wenn ihr mich fragt entbehrt das jeglicher Logik...

    Hat ein DataGrid vielleicht irgendeine versteckte Funktion? Oder könnte es am Ende sogar das

    vm:VisualHelper.EnableRowsMove="True"

    daran Schuld sein?

    Zum Verständnis: Das ist eine Klasse, die mir das Verschieben von Datensätzen im DataGrid nach oben oder unten mit der Maus dient...

    Wenn ihr denkt dass das relevant sein könnte kann ichs gern mal posten...

    Edit: Habs grad mal gecheckt der VisualHelper ist es auch nicht...

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

    Nee, das klingt alles eher so, als ob da zweimal dieselbe Klasseninstanz mit denselben Eigenschaften in der Liste gelistet ist. Denn wenn Du Track#123 mit ID 42 einfügst und später nochmal mit der ID#666, dann wird die #666 ja auch für den ersten Eintrag übernommen und die #42 überschrieben.
    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.
    @VaporiZed

    Ich versteh nicht ganz wie sowas passieren kann. Kannst du das bisschen erläutern? Die Klasse hat etliche Eigenschaften, die alle im DataGrid angezeigt werden, darunter halt auch .TrackListID.

    Achso doch einen Unterschied gibts: Die Eigenschaft .TrackListID wird nicht über den Konstruktor gesetzt wie die andern Eigenschaften, sondern bleibt Nothing bzw. 0 bis sie in der obigen Funktion gesetzt wird. Könnte das der Fehler sein?
    Das ist doch so, als ob Du schreibst:

    VB.NET-Quellcode

    1. Button1.Text = "Foo"
    2. Button1.Text = "Bar"
    Da kannst Du vorher oder zwischendurch den Button auch in Listen schieben oder zwischen Form-Instanzen hin- und herschubsen. Wenn der Text neu gesetzt wird, ändert er sich eben.
    Deine Sub AlbumZuPlaylistZufuegen_Execute(obj As Object) nimmt die Track-Objektinstanz entgegen, modifiziert es und schiebt es in eine Dateiliste. Aber das Objekt, ob nun in einer oder in 5 Listen, ist doch immer dasselbe. Änderst Du es an einer Stelle, änderst Du es überall. Du erschaffst ja keine Kopie (mit gleichen Eigenschaften), welche Du irgendwo hinschiebst, sondern Du verwendest laut Code überall dasselbe Objekt.

    Du kannst ja mal auf Knopfdruck einfach mal nur eine sinnfreie TrackID setzen. In der WPF dürfte sich ja die Änderung wahrscheinlich sofort sichtbar machen. Da siehst Du ja dann auch: Änderst Du sie, egal ob unter Zuhilfenahme des Tracks oder indirekt über die Dateiliste, ändert sie sich sofort überall.
    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.

    VaporiZed schrieb:

    Du erschaffst ja keine Kopie...


    Ah jetzt kommen wir der Sache näher. Davon bin ich nämlich ausgegangen. Das heisst im Umkehrschluss ich sollte dann einfach von meinem Objekt nochmal eine Kopie zwischenspeichern sagen wir in einer Dim FooBar As ViewModel.MP3FileInfoVM und die dann modifizieren und an die Playlist weitergeben dann sollte das gegessen sein oder?

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

    Richtig. Oder Du bekommst es hin, dass Du die Daten anders organisierst. Ich würd in meinen Projekten wohl eher ein Datenpaket haben, bei dem ich auf den Track verweise (z.B. mittels ID) und dann noch eine TrackID hinzufüge.

    VB.NET-Quellcode

    1. Class TrackDataPack
    2. Property TrackID As Integer
    3. Property UniqueTrackIdInCurrentLeftDeck As Integer
    4. End Class
    So bleibt der Track selbst unbehelligt und es kann trotzdem eine Zusatzinfo vergeben werden. Denn: Was interessiert es das 8. Lied von der 15. CD von Madonna, dass es in Deinem Programm die TrackID 187 bekommt?
    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.

    kafffee schrieb:

    Du machst also auch einen Musikplayer? Baust du auch auf die bass.dll auf? Wenn du Fragen hast gerne stellen, vielleicht kann ich dir zur Abwechslung auch mal unter die Arme greifen...


    Ich bau jetzt sogar Video ein, verkommt immer mehr zum Multi-Mediaplayer. :D Für Video nehm ich die Bibliothken vom VLC. Hatte das mit dem WPF MediaElement versucht, aber das frisst nicht alles an Codecs. Wenn ich es noch gebacken bekomme Sound-Effekte(Equalizer usw.) mit der Libvlc hinzubekommen, werfe ich die Bass raus, die Libvlc kann ja fast alle Codecs abspielen.

    Edit:
    Den Vorschlag mit GUID von @RodFromGermany könnte man nutzen, aber bei einer Playlist finde ich das weniger gut. Weil man dadurch(im vergleich zu int/uint) die Möglichkeit verliert, wieder in der Reihenfolge zu sortieren, nach der die Titel hinzugefügt wurden.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

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

    DTF schrieb:

    in der Reihenfolge zu sortieren, nach der die Titel hinzugefügt wurden.
    Das wäre bei mir die unsortierte Reihenfolge.
    Eine Sortieroption "in der Hinzufüge-Reihenfolge" ist mir noch nicht untergekommen.
    @kafffee Ich habe jetzt diesen Thread nicht intensiv verfolgt.
    Wenn Du testweise parallel mit einem Dictionary arbeiten würdest, bekämst Du sofort mit, wo der zweite Eintrag eingefügt wird.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    Eine Sortieroption "in der Hinzufüge-Reihenfolge" ist mir noch nicht untergekommen.


    Ich verwende DataGrid's, die Playlist ID ist bei mir sichtbare Column, von daher kann ich das so sortieren. Hab mein Programm mehr wie eine Datenbank-Ansicht gehalten. Weniger was für's Auge, eher eine Datenbankansicht die Medien wiedergeben kann.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    @VaporiZed
    Hab mir das genau angeschaut nochmal. Ich verwende doch wirklich schon bereits eine Kopie oder?:

    VB.NET-Quellcode

    1. Dim Objekt As ViewModel.MP3FileInfoVM = CType(obj, ViewModel.MP3FileInfoVM)


    Ich verwende nicht obj direkt... oder versteh ich da was falsch?

    Kannst du dein Code-Schnipsel aus Post 11 nochmal erläutern? Ich befürchte das ist bei mir nicht möglich (wenn ich dich richtig verstehe), denn ich habe eine OC mit allen Musiktiteln, dann eine Listbox mit den (gefilterten) Musiktiteln (Suchfunktion) aus der ich dann in die Playlist adde. Die Sammlung mit allen Musiktiteln kann aber auch während der Laufzeit sich ändern, also müsste ich in deinem Beispiel TrackID auch dynamisch erzeugen oder...?

    RodFromGermany schrieb:

    wo der zweite Eintrag eingefügt wird.


    Was meinst du mit wo? Kannst du mir zum besseren Verständnis ne Codeschnipsel schreiben?

    @DTF
    Okay vom VLC-Player hab ich keinen Plan....
    Ne, ein Casten von Object zu Irgendwas erzeugt keine Kopie, sondern einfach nur die für den Compiler in einen bestimmten Typ umgewandelte Originalinstanz. Würdest Du mit Option Strict Off arbeiten, bräuchtest Du den Cast nicht und Du könntest mit der Object-Variable auf TrackID zugreifen. Der Cast ist nur für die Typpsicherheit. Es erstellt keine Kopie.
    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.

    kafffee schrieb:

    ne Codeschnipsel schreiben?

    VB.NET-Quellcode

    1. Dim dict = New Dictionary(Of Integer, String)
    2. dict.Add(1, "Titel 1")
    3. dict.Add(2, "Titel 2")
    4. dict.Add(1, "Titel 1") ' der knallt, weil Nr. 1 schon da ist
    Es kommt natürlich darauf an, wo in Deinem diese Elemente hinzugefügt werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VaporiZed

    Aber das war schon so gedacht von dir oder?:

    VB.NET-Quellcode

    1. ​Private Sub MusiktitelZuPlaylistZufuegen_Execute(obj As Object)
    2. Dim Objekt As ViewModel.MP3FileInfoVM = CType(obj, ViewModel.MP3FileInfoVM)
    3. Dim AudioTrack As ViewModel.MP3FileInfoVM = Objekt
    4. 'Objekt.TrackListID = 0
    5. Dim StartID As Integer = 1
    6. 'Dim ID As Guid
    7. If Not Deck2IstSelektiert Then
    8. If LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Count > 0 Then
    9. StartID = LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Max(Function(x) x.TrackListID) + 1
    10. End If
    11. AudioTrack.TrackListID = StartID
    12. LayerViewModel.PlattendecksViewModel.DeckLeft.Playlist.Add(AudioTrack)
    13. Else
    14. If LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Count > 0 Then
    15. StartID = LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Max(Function(x) x.TrackListID) + 1
    16. End If
    17. AudioTrack.TrackListID = StartID
    18. LayerViewModel.PlattendecksViewModel.DeckRight.Playlist.Add(AudioTrack)
    19. End If
    20. End Sub
    Ich könnte mir vorstellen, dass ein Denkfehler im Datenmodell vorliegt.
    Sind mehrere Decks vorgesehen, mit je einer Playlist, so braucht man PlaylistItem-Datensätze, deren jeder sowohl auf ein Mp3Item verweist als auch auf das Deck, dessen PlayList das PlaylistItem angehört.

    "Duplizieren von Mp3Item" klingt ziemlich besorgniserregend in meinen Ohren.

    Also ich glaub, es sollte mal das Datenmodell ausdiskutiert werden, was deiner Anwendung zugrundeliegt.
    @ErfinderDesRades

    Ja klar gerne.

    Also ich hab eine Datenklasse ViewModel.MP3FileInfoVM, da sind die Properties jeder Audiodatei drin, also Dateiname, Interpret, Album usw. Diese werden über den Konstruktor gesetzt, bis auf die Eigenschaft TrackListID. Diese bleibt uninitialisiert.
    Für jede Audiodatei dann ein Datensatz.
    Meine zwei Decks mit den Playlisten drin sind jeweils Instanzen desselben ViewModels.

    Die den Playlisten zu Grunde liegenden Datensätze sind ebenfalls vom Typ ViewModel.MP3FileInfoVM.

    Also sollen beim Adden von Tracks zu den Playlisten einfach eine Kopie des Datensatzes mit einer ID versehen werden und dann einer der Playlisten zugefügt werden...