Bug in CollectionView Filterlogik

  • WPF MVVM

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

    Bug in CollectionView Filterlogik

    Hallo allerseits an diesem wunderschön grauen Novembertag,

    nach längerer Zwangspause bin ich mal wieder online ;)

    ich habe ein Problem mit einer Filterlogik, bzw. zweier Filterlogiken im Zusammenspiel. Ich glaube jedenfalls es liegt an der Filterlogik, kann aber auch andere Ursachen haben...

    Der Zusammenhang ist recht komplex, aber ich versuch mal mein Bestes das zu erklären:

    Ich habe drei Listboxen: Interpeten, Alben und Musiktitel. Diese sind jeweils an CollectionViews gebunden: AnzuzeigendeInterpreten, AnzuzeigendeAlben und AnzuzeigendeMusiktitel.

    Die relevanten Filerlogiken der CollectionViews sehen so aus:

    VB.NET-Quellcode

    1. Private Function AnzuzeigendeAlben_Filter(obj As Object) As Boolean
    2. Dim Objekt As MP3FileInfo = DirectCast(obj, MP3FileInfo)
    3. Dim IstErlaubt = Not Objekt.Stream
    4. If Not IstErlaubt Then Return IstErlaubt
    5. If Not String.IsNullOrEmpty(TextFilter) Then
    6. IstErlaubt = Objekt.Interpret.ToLower.Contains(TextFilter) OrElse Objekt.Album.ToLower.Contains(TextFilter)
    7. If Not IstErlaubt Then Return IstErlaubt
    8. ElseIf AusgewählterInterpret IsNot Nothing Then
    9. If Objekt.Interpret = _AusgewählterInterpret.Interpret Then
    10. IstErlaubt = True
    11. Else
    12. IstErlaubt = False
    13. End If
    14. If Not IstErlaubt Then Return IstErlaubt
    15. End If
    16. For Each selGenre In AnzuzeigendeGenres.Where(Function(g) Not g.IstSelektiert)
    17. If Objekt.Genre = selGenre.Genre Then Return False
    18. Next
    19. Return IstErlaubt
    20. End Function
    21. Private Function AnzuzeigendeMusiktitel_Filter(obj As Object) As Boolean
    22. Dim Objekt As MP3FileInfo = DirectCast(obj, MP3FileInfo)
    23. Dim IstErlaubt = Not Objekt.Stream
    24. If Not IstErlaubt Then Return IstErlaubt
    25. If Not String.IsNullOrEmpty(TextFilter) Then
    26. IstErlaubt = Objekt.Interpret.ToLower.Contains(TextFilter) OrElse Objekt.Album.ToLower.Contains(TextFilter) OrElse Objekt.Musiktitel.ToLower.Contains(TextFilter)
    27. ElseIf AusgewähltesAlbum IsNot Nothing AndAlso AusgewählterInterpret Is Nothing Then
    28. If Objekt.Album = _AusgewähltesAlbum.Album Then
    29. IstErlaubt = True
    30. Else
    31. IstErlaubt = False
    32. End If
    33. ElseIf AusgewähltesAlbum Is Nothing AndAlso AusgewählterInterpret IsNot Nothing Then
    34. If Objekt.Interpret = _AusgewählterInterpret.Interpret Then
    35. IstErlaubt = True
    36. Else
    37. IstErlaubt = False
    38. End If
    39. ElseIf AusgewähltesAlbum IsNot Nothing AndAlso AusgewählterInterpret IsNot Nothing Then
    40. If Objekt.Album = _AusgewähltesAlbum.Album Then
    41. IstErlaubt = True
    42. Else
    43. IstErlaubt = False
    44. End If
    45. End If
    46. If Not IstErlaubt Then Return IstErlaubt
    47. For Each selGenre In AnzuzeigendeGenres.Where(Function(g) Not g.IstSelektiert)
    48. If Objekt.Genre = selGenre.Genre Then Return False
    49. Next
    50. Return IstErlaubt
    51. End Function


    Diese Properties sind an die .SelectedItem der Listboxen gebunden:

    VB.NET-Quellcode

    1. Public Property AusgewählterInterpret As MP3FileInfo
    2. Get
    3. Return _AusgewählterInterpret
    4. End Get
    5. Set(value As MP3FileInfo)
    6. If value IsNot Nothing Then
    7. AusgewähltesAlbum = Nothing
    8. _AusgewählterInterpret = value
    9. RaisePropertyChanged()
    10. AnzuzeigendeAlben.Refresh()
    11. AnzuzeigendeMusiktitel.Refresh()
    12. End If
    13. End Set
    14. End Property
    15. Public Property AusgewähltesAlbum As MP3FileInfo
    16. Get
    17. Return _AusgewähltesAlbum
    18. End Get
    19. Set(value As MP3FileInfo)
    20. If value IsNot Nothing Then
    21. _AusgewähltesAlbum = value
    22. RaisePropertyChanged()
    23. AnzuzeigendeMusiktitel.Refresh()
    24. MessageBox.Show("Album geändert")
    25. End If
    26. End Set
    27. End Property


    Nun sollen, wenn ein Interpret in der Listbox ausgewählt wird, alle Alben und Musiktitel des jeweiligen Interpreten in den entsprechenden anderen Listboxen angezeigt werden.
    Und dazu: Wenn ein Album ausgewählt wird, alle Musiktitel...

    Funktioniert auch, beim ersten Mal. Aber wenn ich ein Album aussuche und dann wieder einen Interpret, scheint die Listbox mit den Musiktiteln nicht sichtbar aktualisiert zu werden... Die der Alben aber schon. Ich glaube da kommt sich gegenseitig was in die Quere...

    So, ich hoffe, ich habe alle relevanten Codestellen gepostet, aber ich habe mit Sicherheit was vergessen. Zur Sicherheit lade ich das Projekt mal hoch, dann kann man auch ausprobieren, was ich meine... Der relevante Code ist in der SucheViewModel.vb
    Dateien
    Hallo

    kafffee schrieb:

    scheint die Listbox mit den Musiktiteln nicht sichtbar aktualisiert zu werden... Die der Alben aber schon


    Weil du die Titelliste ja auch nicht aktualisierst.
    Beim auswählen eines Interpreten setzt du mit ​AusgewähltesAlbum = Nothing zwar korrekt auf null (Nothing) aber das ignorierst du schlicht weil du im Setter (hier dein Setter)

    VB.NET-Quellcode

    1. If value IsNot Nothing Then
    2. AusgewählterInterpret = Nothing
    3. _AusgewähltesAlbum = value
    4. RaisePropertyChanged()
    5. AnzuzeigendeMusiktitel.Refresh()
    6. MessageBox.Show("Album geändert")
    7. End If

    Einfach drübersprichst, der Code wird ja nur ausgeführt wenn das Album NICHT Nothing ist.

    VB.NET-Quellcode

    1. AusgewählterInterpret = Nothing
    2. If value IsNot Nothing Then
    3. _AusgewähltesAlbum = value
    4. RaisePropertyChanged()
    5. End If
    6. AnzuzeigendeMusiktitel.Refresh()
    7. MessageBox.Show("Album geändert")


    So sollte es klappen. Das solltest du aber gemerkt haben da du keine Messagebox angezeigt bekommen hast.
    Ein kleiner Tipp am Rande, lass das mit den Messageboxen (Abgesehen davon das du die ja gar nicht verwenden dürftest bei MVVM (aber das ist wieder ein anderes Thema)) und verwende lieber ​Debug.WriteLine("Album geändert") für sowas. Das musst du dann bei "Auslieferung" auch nicht mühsam auskommentieren oder löschen da der Compiler im Release drüberspringt.

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

    @Nofear23m

    Hey Sascha. Erstmal nachträglich nen schönen 1. Advent. Sry dass ich erst jetzt schreib, ich hatte mal wieder nicht den Kopf zu programmieren.

    Irgendwie komm ich mit deinem Post nicht ganz klar. Du schreibst:

    Nofear23m schrieb:

    Beim auswählen eines Interpreten...


    Veränderst dann aber den Code von AusgewähltesAlbum

    Selbst wenn ich statt AusgewählterInterpret = Nothing AusgewähltesAlbum = Nothing nehme funktioniert das nicht wie ich es will.

    Mein Code den ich jetzt habe ist:

    VB.NET-Quellcode

    1. Public Property AusgewählterInterpret As MP3FileInfo
    2. Get
    3. Return _AusgewählterInterpret
    4. End Get
    5. Set(value As MP3FileInfo)
    6. AusgewähltesAlbum = Nothing
    7. If value IsNot Nothing Then
    8. _AusgewählterInterpret = value
    9. RaisePropertyChanged()
    10. End If
    11. AnzuzeigendeAlben.Refresh()
    12. AnzuzeigendeMusiktitel.Refresh()
    13. End Set
    14. End Property
    15. Public Property AusgewähltesAlbum As MP3FileInfo
    16. Get
    17. Return _AusgewähltesAlbum
    18. End Get
    19. Set(value As MP3FileInfo)
    20. If value IsNot Nothing Then
    21. _AusgewähltesAlbum = value
    22. RaisePropertyChanged()
    23. AnzuzeigendeMusiktitel.Refresh()
    24. End If
    25. End Set
    26. End Property


    Ich habe natürlich auch andere mir nur denkbare Konstellationen probiert aber da bekam ich dann Probleme mit Rekursion und StackOverFlow...

    Du hast bestimmt nur einen Flüchtigkeitsfehler gemacht...

    Grüsse aus Kirchheim :)
    Lese nochmals meinen Post GENAU.

    kafffee schrieb:

    Veränderst dann aber den Code von AusgewähltesAlbum

    Richtig, aber im Code des Setters von ​AusgewähltesAlbum veränderst du nunmal den Interpreten mit ​AusgewählterInterpret = Nothing

    Änderst du einfach den Code wie von mir beschreiben funktioniert es doch. Zumindest bei mir. Ansonsten musst du Bescheid geben was genau denn nun nicht so funktioniert wie du es willst.

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

    Nofear23m schrieb:

    Änderst du einfach den Code wie von mir beschreiben funktioniert es doch. Zumindest bei mir. Ansonsten musst du Bescheid geben was genau denn nun nicht so funktioniert wie du es willst.


    Yep ich glaube da ham wir uns falsch verstanden. Hier mal was genau ich meine:

    (1) Starte das Programm.
    (2) Wähle den Interpreten DMX aus:
    -Es erscheint in den Alben "Great Depression" und in den Titeln "Calling Up" und "Trina Moe"
    >>>>so soll es auch sein.
    (3) Klicke nun in den Alben auf "Great Depression"
    >>>>> Die Titel bleiben unverändert... so soll es ebenfalls sein.
    (4) Klicke nun in den Interpreten auf "Eminem".
    >>>>>>> Die Alben werden korrekt angezeigt ("Marshall Mathers LP"), aber die Titel zeigen immer noch "Calling Up" und "Trina Moe" an. >>>> was natürlich falsch ist.

    Warum also ist das so? Direkt nach dem Programmstart geht's doch? Wenn ich die gleiche Änderung in der AusgewählterInterpret mache, gibt es leider einen Stack Overflow...

    Zur Sicherheit mal der Code so, wie ich dich verstanden habe:

    VB.NET-Quellcode

    1. ​Public Property AusgewählterInterpret As MP3FileInfo
    2. Get
    3. Return _AusgewählterInterpret
    4. End Get
    5. Set(value As MP3FileInfo)
    6. If value IsNot Nothing Then
    7. AusgewähltesAlbum = Nothing
    8. _AusgewählterInterpret = value
    9. RaisePropertyChanged()
    10. AnzuzeigendeAlben.Refresh()
    11. AnzuzeigendeMusiktitel.Refresh()
    12. End If
    13. End Set
    14. End Property
    15. Public Property AusgewähltesAlbum As MP3FileInfo
    16. Get
    17. Return _AusgewähltesAlbum
    18. End Get
    19. Set(value As MP3FileInfo)
    20. AusgewählterInterpret = Nothing
    21. If value IsNot Nothing Then
    22. _AusgewähltesAlbum = value
    23. RaisePropertyChanged()
    24. End If
    25. AnzuzeigendeMusiktitel.Refresh()
    26. End Set
    27. End Property

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

    OK, jetzt sehe ich was du meinst.

    Die StackOverflowException bekommst du weil der Code ja im Kreis läuft.

    Bemerkung: Ich weis es wurde dir schon mehrmals gesagt soweit ich weis aber wenn du deine Variablen, Methode und Properties schon in Deutsch benamst dann bitte lass wenigstens so sachen wie Umlaute, das kann unter umständen (gerne unter XAML) zu erheblichen Problemen führen.

    Ändere den Code wie folgt:

    VB.NET-Quellcode

    1. Public Property AusgewählterInterpret As MP3FileInfo
    2. Get
    3. Return _AusgewählterInterpret
    4. End Get
    5. Set(value As MP3FileInfo)
    6. _AusgewähltesAlbum = Nothing
    7. If value IsNot Nothing Then
    8. _AusgewählterInterpret = value
    9. RaisePropertyChanged()
    10. AnzuzeigendeAlben.Refresh()
    11. AnzuzeigendeMusiktitel.Refresh()
    12. End If
    13. End Set
    14. End Property
    15. Public Property AusgewähltesAlbum As MP3FileInfo
    16. Get
    17. Return _AusgewähltesAlbum
    18. End Get
    19. Set(value As MP3FileInfo)
    20. _AusgewählterInterpret = Nothing
    21. If value IsNot Nothing Then
    22. _AusgewähltesAlbum = value
    23. RaisePropertyChanged()
    24. End If
    25. AnzuzeigendeMusiktitel.Refresh()
    26. Debug.WriteLine("Album geändert")
    27. End Set
    28. End Property


    Grüße und gute N8
    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. ##

    Yep schon besser. Aber wenn ich jetzt z.B. zuerst DMX auswähle, dann auf Great Depression klicke und dann auf Eminem klicke (also auf den Interpreten, der noch nicht ausgewählt ist, dann erscheinen wieder alle Musiktitel, und nicht nur die von Eminem (Stan), also wie wenn überhaupt kein Interpret ausgewählt ist. Klar, denn wenn wir das Album ändern wird ja _AusgewählterInterpret wieder auf Nothing gesetzt und somit wird der Code unter If value IsNot Nothing nicht ausgeführt. Das kann man bestimmt irgendwie beheben, aber meine Kreativität bzw. Vorstellungskraft stösst da an ihre Grenzen.

    Ich habs mir jetzt noch eine Weile angeschaut und das Einzige was mir noch dazu einfällt ist:
    Ich habe bemerkt, dass der ausgewählte Interpret bei Klick auf ein Album natürlich nicht deselektiert wird und andersherum. Was also, wenn man statt _AusgewählterInterpret = Nothing bzw. _AusgewähltesAlbum = Nothing auf Nummer sicher geht, und anstatt dessen die jeweiligen SelectedIndex die man natürlich vorher auch gebunden hat auf -1 setzt, so dass auch im UI die Items deselektiert werden. Aber da wird man dann wahrscheinlich wieder in die Rekursion kommen...

    Fällt dir noch was dazu ein?

    Edit:
    Ahhhhh jetzt ja... Kommando zurück... Das _AusgewählterInterpret = Nothing brauchen wir nicht, also weggelassen und schwups gehts...

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