CollectionViewSource wird nicht korrekt in DataGrid angezeigt

  • WPF

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von Vatter.

    CollectionViewSource wird nicht korrekt in DataGrid angezeigt

    Hallo, liebe Gemeinde,
    ich habe ein global verfügbares Mainmodel-Objekt, das einen Datacontext mit (u.a.) einer Tabelle "Personen" enthält. Nach dem Laden wird einer CollectionViewSource (Property PersonenViewSource) diese Tabelle als Source zugewiesen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class MainModel
    2. Public Property PersonenViewSource As New CollectionViewSource
    3. Public Property Laden As New RelayCommand( _
    4. Sub()
    5. If context IsNot Nothing Then context.Dispose()
    6. context = New MyDataDataContext("Data Source=" & _DataFile.FullName)
    7. context.Log = Console.Out
    8. If Not _DataFile.Exists Then
    9. context.CreateDatabase()
    10. End If
    11. PersonenViewSource.Source = context.Personen 'hier erfolgt die Zuweisung
    12. Debug.Print("**** nach dem Laden:")'und hier wird der Inhalt zum Test (korrekt) ausgegeben
    13. For Each temp In PersonenViewSource.View
    14. Dim a As Personen = CType(temp, Personen)
    15. Debug.Print(a.Vorname & " ; " & a.Name)
    16. Next
    17. OnPropertyChanged("context")
    18. OnPropertyChanged("PersonenViewSource")
    19. End Sub)

    Die Bindung erfolgt problemlos über Designerunterstützung im Usercontrol.XAML. Alle verfügbaren Eigenschaften werden korrekt beim Einrichten der Bindung angezeigt.
    Spoiler anzeigen

    XML-Quellcode

    1. <UserControl x:Class="UC_Personen"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. .
    4. .blablabla
    5. .
    6. xmlns:my="clr-namespace:Dispatcher"
    7. DataContext="{StaticResource MainModel}">
    8. <DataGrid Name="DG_Personen"
    9. Grid.Column="0"
    10. Grid.Row="1"
    11. AutoGenerateColumns="false"
    12. IsSynchronizedWithCurrentItem="True"
    13. ItemsSource="{Binding Path=PersonenViewSource}" >
    14. <DataGrid.Columns>
    15. <DataGridTextColumn Header="Vorname" Binding="{Binding Path=Vorname}" Width="0,5*"/>
    16. <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="0,5*"/>
    17. </DataGrid.Columns>
    18. </DataGrid>

    Das Datagrid bleibt komischerweise leer. Also habich einen Testbutton eingerichtet, in dem ich die View der PersonenViewSource auflisten lasse.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Debug.Print(vbCrLf & "aus Personenviewsource: ")
    2. For Each temp In Application.DataInstanz.PersonenViewSource.View
    3. Dim a As Personen = CType(temp, Personen)
    4. Debug.Print(a.Vorname & " ; " & a.Name)
    5. Next
    Auch hier erfolgt die korrekte Listung der Namen.
    Aber die Datagridview.Itemsource-Eigenschaft ist lt. Debugging Nothing!
    Ich habe nun im Sub New des Usercontrol die Datagridview.Itemsource-Eigenschaft= PersonenViewSource.View gesetzt. Jetzt werden die Einträge angezeigt.
    Aber warum ist das so?
    - Was unterscheidet die Bindung des Datacontext über eine CollectionViewSource im XAML von einer Applicationsweit verfügbaren mit VB erstellten CollectionViewSource?
    - Nach dem Laden über einen Button (Laden-Relaycommand) wird diese VB-CollectionViewSource nicht aktualisiert (wegen context.Dispose und context-Neuinstanzierung vermutlich) Im Mainmodel hab ich aber keinen Verweis auf das Control(Datagrid und Co) um die View neu zuzuweisen, und des möcht ich ja eigentlich auch nicht.
    Hat da wer nen Tipp, wie ich das gebacken bekomm?

    Achso, das warum das ganze hab ich fast vergessen: Ich möchte im applikationsweit verfügbaren Mainmodel-Objekt eine CollectionViewSouce zur Verfügung haben, die ich von jedem Fenster aus binden kann und deren .View.Filter-Eigenschaft ich nutzen kann.

    Dank für eure Mühe

    Vatter
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    CollectionViewSource ist ein Wrapper um ein ListCollectionView, welcher explizit für Xaml vorgesehen ist. Habich iwo auf Msdn mal aufgeschnappt.
    Wenn du die Auflistung im Viewmodel halten willst (was ich seit einiger Zeit favorisiere), dann nimm dort keine CollectionsViewSource, sondern direkt eine ListCollectionView
    Hm, bin irgendwie zu blöde...
    Auch eine Property as Listcollectionview oder Collectionview bringt mich nicht voran. In der Itemsource eines Datagrid ist das Dinge zwar verfügbar, aber für die Spaltenbindung tauchen alle mögliche Propertys auf, nur eben nicht die Spalten der Entität. Man kann zwar deren Namen da als Path angeben, was denn auch angezeigt wird, aber kann keine Zeile editieren oder löschen oder hinzufügen... :(
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Du setzt den DataContext falsch...

    Quellcode

    1. DataContext="{StaticResource MainModel}"


    Das stimmt schon mal sicher nicht. a) würde ich das nicht über StaticResource machen b) fehlt garantiert ein namespace (es sei MainViewModel ist im WPF Standartnamespace -> also nein :))

    EDIT: ou da war ich zu schnell... grad bisschen durcheinander. Bei Resourcen brauchste das ja nicht. Machs trotzdem mal ohne das StaticResource. Um auf nummer sicher zu gehen einfach mal im CTOR setzen (keine Angst das ist auch mit MVVM erlaubt)


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Hi @thefiloe, der Datacontext passt schon so. Wird im Designer unter "Resourcen übernehmen" > "lokal:" angeboten. Das Mainmodel-Objekt wird in der App.xaml erzeugt und in der App.vb über Findresource Shared applikationsweit verfügbar gemacht.
    Die Bindung direkt an die context-Property des Mainmodels ("Public Property context As MyDataDataContext") funzt ja auch problemlos. Nur hab ich auf diese Weise keine Möglichkeit (oder kenne sie nicht) wie ich eine solche Ansicht in irgendeiner Weise filtern könnte. Dazu bräuchts die CollectionView oder deren Verwandte. Die bekomm ich aber nur im Windows.vb mit Findresources heraus. Eine Propertie im Mainmodel wär mir lieber.

    Aber wer ist bitte CTOR?
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Ctor ist konstruktor.
    Wieso willst du überhaupt eine CollectionView binden?
    Ich habe bessere Erfahrungen mit einer ObservableCollection<T> im Viewmodel und einer Eigenschaft mit Typ T wo das selecteditem dran gebunden ist.
    Kannste mich gern mal in Skype adden dann kann ich dir sicher weiterhelfen hab das schon oft gemacht das muss auch bei dir klappen.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Ich denke, ich bin wieder etwas schlauer dank MSDN. Ich hätte mich da gleich bei den "Gewußt wie"-Themen durchhangeln sollen. Sry

    Nach meinen Recherchen erhält man die View des Steuerelementes nicht nur über Findresources sondern viel einfacher vom Steuerelement und dessen Datacontext oder Itemsources selbst.
    Also erfolgt die Bindung des Controls zunächst direkt an die Auflistung (in meinem Fall an den Mydatacontext meines Datenmodels) via Designer.
    Im Codebehind wird dann die Collectionview aus dem Control gesaugt, um sie zum Navigieren oder Filtern zu benutzen.
    Hier mal ein primitives Beispiel für ne Navigation:

    VB.NET-Quellcode

    1. Dim myCollectionView As CollectionView
    2. Private Sub Klick_rück(sender As System.Object, e As System.Windows.RoutedEventArgs)
    3. myCollectionView = CType(CollectionViewSource.GetDefaultView(DG_Personen.ItemsSource), CollectionView)
    4. myCollectionView.MoveCurrentToPrevious()
    5. End Sub
    6. Private Sub Klick_vor(sender As System.Object, e As System.Windows.RoutedEventArgs)
    7. myCollectionView = CType(CollectionViewSource.GetDefaultView(DG_Personen.ItemsSource), CollectionView)
    8. myCollectionView.MoveCurrentToNext()
    9. End Sub

    Die Instanz besorg ich mir jedesmal neu, da nach dem Ausführen des Laden-Commands das MyDatacontext-Objekt neu instanziert wird. damit hängt myCollectionview in der Luft und hat keine Auswirkung mehr auf das Control

    VB.NET-Quellcode

    1. Private _DataFile As New FileInfo("MyDB.sdf")
    2. Public Property context As MyDataDataContext
    3. 'Command DB Laden
    4. Public Property Laden As New RelayCommand( _
    5. Sub()
    6. 'hier wird die Instanz vernichtet und das Binding offenbar neu initialisiert
    7. If context IsNot Nothing Then context.Dispose()
    8. context = New MyDataDataContext("Data Source=" & _DataFile.FullName)
    9. context.Log = Console.Out
    10. If Not _DataFile.Exists Then
    11. context.CreateDatabase()
    12. End If
    13. OnPropertyChanged("context")
    14. End Sub)

    Es scheint aber für ein Reload des Context keine andere Variante zu geben, die ihn einfach neu befüllt. Will heißen, ich finde sie nicht... :huh:
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Ich bin schon seit glaub 3 Posts total verwirrt, weil ich habe eine Anwendung, wo das erwiesenermaßen und tadellos funktioniert mit einem ListCollectionView im Viewmodel.
    Und das ist auch wunderfein, denn ich kann dieser ListCollectionView im Viewmodel Filter setzen, und sortieren und gruppieren, und muß mir nix iwo herholen, und keine einzige Typumwandlung durchführen.
    Also MVVM vom Feinsten: es kommt ein "SetzeFilter"-RelayCommand im Viewmodel an, und ich kann mir die dollsten Gemeinheiten ausdenken - auch mit Bezügen zu anneren Daten - weil ich bin ja im Viewmodel, und nicht im Codebehind.
    Nu probier ich seit gestern, das Prinzip auf mein Wpf-Tut anzuwenden, aber dort im Xaml werden die bindebaren Properties nicht angeboten, die in meine annere App wie selbstverständlich verfügbar sind.

    Genauer:
    Binding an eine typisierte IList (List(of T) oder ObservableCollection(of T) oder auch DataContext-Table(Of T)) bietet ja immer die Properties der Elemente der Liste an.

    Nur scheint er die ListCollectionView in meim neuen Projekt nicht als IList aufzufassen, sondern bietet nur die Properties der ListCollectionView selber an (Count, SortDescriptions, ...) - nicht aber die Properties der Elemente, die drinne sind.
    Also im einen Projekt funztes, im anneren nich :(

    Ich forsche daran.

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

    ErfinderDesRades schrieb:

    Nur scheint er die ListCollectionView in meim neuen Projekt nicht als IList aufzufassen, sondern bietet nur die Properties der ListCollectionView selber an (Count, SortDescriptions, ...) - nicht aber die Properties der Elemente, die drinne sind.

    Genau das ist mein (primäres) Proplem... Weil wenns der Designer nicht blickt, isses schon merkwürden. Es übrigens auch interessant, dass man so eine ListCollectionView einfach in einer ForEach-Schleife durchlaufen kann, (ForEach t in myListCollectionView...), t mit Ctype einfach umwandeln kann und per Debug.Print die Tabelle anzeigen kann. Im Ausgabefenster kommt dann eine Warnung vorneweg, dass (sinngemäß lt.Google-Übersetzer) dieser direkte Zugriff buggy ist und u.U. Probleme bereiten kann und man soll eine abgeleitete Klasse verwenden.
    System.Windows.Data Warning: 52 : Using CollectionView directly is not fully supported. The basic features work, although with some inefficiencies, but advanced features may encounter known bugs. Consider using a derived class to avoid these problems.
    Scheint also generell was im Busch zu sein.
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    ListCollectionView ist doch "a derived class to avoid these problems." Oder nicht?

    Hier mal meine bisherige Übung.
    Wie gesagt: alles scheint mir 100% identisch zu der App, wo das funktioniert.
    Das 2. Datagrid ist übrigens zum Vergleich an die ObservableCollection direkt gebunden, dass man die Unterschiede der Bindings der DG-Columns im Designer sieht.
    Laufen tun beide.
    Dateien

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

    Hurraa! - ich hab ihn!

    :) :) :) :) :)
    Der Bug ist: Das Binding funzt nur korrekt, wenn im Mainmodel der ListCollectionView ein Filter mitgegeben wird:

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Imports System.IO
    3. Imports GalaSoft.MvvmLight
    4. Imports GalaSoft.MvvmLight.Command
    5. Imports System.ComponentModel
    6. Public Class MainModel : Inherits MainModelBase(Of MainModel)
    7. Private _Folder As New DirectoryInfo("..\..\")
    8. Public Property __FileInfos As New ObservableCollection(Of FileInfo) From {New FileInfo("C:Gibsnich\gibsÜberhauptNich.Txt")}
    9. Public Property FileInfos As New ListCollectionView(__FileInfos) With {.Filter = Function(o) True}
    10. Public Sub New()
    11. If IsProvisional Then Return
    12. __FileInfos.Clear()
    13. _Folder.GetFiles.ForEach(AddressOf __FileInfos.Add)
    14. End Sub
    15. End Class


    Edit: Der Bug ist sogar noch abstruser: Es reicht, wenn irgendeiner public Property ListCollectionView ein Filter angedreht wird!

    VB.NET-Quellcode

    1. Imports System.Collections.ObjectModel
    2. Imports System.IO
    3. Imports GalaSoft.MvvmLight
    4. Imports GalaSoft.MvvmLight.Command
    5. Imports System.ComponentModel
    6. Public Class MainModel : Inherits MainModelBase(Of MainModel)
    7. Private _Folder As New DirectoryInfo("..\..\")
    8. Public Property __FileInfos As New ObservableCollection(Of FileInfo) From {New FileInfo("C:Gibsnich\gibsÜberhauptNich.Txt")}
    9. Public Property Dummi As New ListCollectionView({99}) With {.Filter = Function(o) True}
    10. Public Property FileInfos As New ListCollectionView(__FileInfos)
    11. Public Sub New()
    12. If IsProvisional Then Return
    13. __FileInfos.Clear()
    14. _Folder.GetFiles.ForEach(AddressOf __FileInfos.Add)
    15. End Sub
    16. End Class
    Dateien

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

    Wahrscheinlich stell ich mich absolut zu doof an. Ich kann dein Projekt zwar öffnen und anschmeißen, aber im Designer geht ganischt (gugge Bild)
    da ich den Verdacht habe, dass es an fehlender Galasoft-Gschichte liegt, hab ich des runnergeladen und installert... also die 3er und die 4er Beta probiert, aber weder kann ich in deinen Projekten was sehen, weil Mainmodel-Instanz nicht erzeucht wern kann, noch tauchen die Vorlagen bei neuem Projekt erstellen auf. ICH BIN ÄUSSERST VRUSTRIERT, zum Deibel nochama.. X(
    Dein Beitrag hat sich jetz mit meinem übergeschnitten, werd ich gleich ma reinschaun.
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Zu 1. und 2. Ja
    Galasoft rausschmeißen? ausm Projekt, oder wie? Und wie einbinden? Sry, wenn ich mich so anstelle, aber die Galasoft-Vorlagen habich jetzt unter Expressions in eigene Dateien gefunden, is aber alles C

    Edit:
    Ich hab jetzt dein Beispiel mit dem Filter in mein Projekt reingetan getan und bin BEGEISTERT! :thumbsup: nachdem ich dann auch das OnPropertyChanged-Event gefeuert hab, weil sich sonst nach dem Reload nix aktualisiert hat :rolleyes:

    Aber auf den Trick mitm Filter muß man erstma kommen. Hut ab!
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:

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

    Leider hat auch das Entfernen des Verweises und das neu hinzufügen nix gebracht. Werd morgen nochma weiterprobieren. Aber wie gesagt (Edit von vorhin) hab ichs dank deiner Hilfe schon wunschgemäß in den Griff bekommen.

    Ich wünsch noch nen schönes Wochenende und guts Nächtle :)
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:
    Das mitte Dll kann am VS liegen. Also wenn du mit 2008 unterwegs bist (wies in deim Profil steht) wäre alles klar (ausser, warum dus ühaupt öffnen konntest).

    Ansonsten stresst mich das mitte Dll.
    Grad heute habich verbreitet, dass diese Dll die einzige ClosedSource ist, die ich verwende, weil die so renommiert sei, täte ich bei der auf Bugfreiheit vertrauen, habich gesagt.
    Sry,
    Asche auf mein Haupt... In meinem Profil stand tatsächlich noch VB2008, das habich total versumpft. Im Beitrag hab ich 2010 angegeben und gedacht (wenn ich schonmal denke) damit wärs erlädicht. Tschuldige

    Könnte das die Ursache sein, dass ich Galasoft ühaupt nicht richtig installert krieg? Es tut zwar so, aber es gibt keine neuen installierten VB-Vorlagen. Das war auch bisher der Grund, warum ich (entgegen deiner Empfehlung) ohne das arbeite.
    Ich versteh auch ehrlich noch nicht so den Sinn davon. das Viewmodel kapselt doch offensichtlich nur die Relayscommands und so Zeugs weg, dass ich nebenher als Klasse liegen hab, oder?
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:

    Vatter schrieb:

    dass ich Galasoft ühaupt nicht richtig installert krieg?

    die Galasoft-Dll brauchste nicht installieren.
    Einfach Verweis hinzufügen - Durchsuchen, und dann die mitgelieferte Galasoft-Datei auswählen.

    Auf seiner Site hatter auchn Download, der die im Global Assembly Cache installiert, und Projektvorlagen und Zeugs. Das funzt auch, aber ich verwende lieber die dumme dll-Datei, weil das ist portabel.

    Vatter schrieb:

    warum ich (entgegen deiner Empfehlung) ohne das arbeite.
    Ich dachte, ich hätte ein RelayCommand in deim Code gesehen - ist das nicht das RelayCommand aus der Galasoft-lib?

    Vatter schrieb:

    Ich versteh auch ehrlich noch nicht so den Sinn davon. das Viewmodel kapselt doch offensichtlich nur die Relayscommands und so Zeugs weg, dass ich nebenher als Klasse liegen hab, oder?
    Ähm - das Viewmodel musst du schon selbst proggen.
    Es ist halt praktisch, dabei von Galasoft.Viewmodelbase zu erben - spart ein paar Zeilen Code.
    Und das Galasoft.RelayCommand ist auch eine praktische Erfindung.

    Nur eben, wenn sich die lib jetzt doch als buggy erweist, macht mich das geneigt, die beiden Sachen eben selbst zu proggen - mehr habich davon auch noch nie genutzt.

    ErfinderDesRades schrieb:

    Ich dachte, ich hätte ein RelayCommand in deim Code gesehen - ist das nicht das RelayCommand aus der Galasoft-lib?

    Ne, ich hab den Code von dem MVVM-Typen, wo du den Artikel verlinkt hast für die Relaycommand-Klasse gemaust und von C nach VB übersetzt. Die Klasse kann ich dann genauso benutzen wie du das bei deinen Relaycommands tust:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class RelayCommand
    2. Implements ICommand
    3. #Region "Events"
    4. Public Event CanExecuteChanged As EventHandler Implements System.Windows.Input.ICommand.CanExecuteChanged
    5. #End Region
    6. #Region "Felder"
    7. ReadOnly _execute As Action(Of Object)
    8. ReadOnly _canExecute As Predicate(Of Object)
    9. #End Region
    10. #Region "Konstruktor"
    11. Public Sub New(ByVal execute As Action(Of Object))
    12. Me.New(execute, Nothing)
    13. End Sub
    14. Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object))
    15. Me._execute = execute
    16. Me._canExecute = canExecute
    17. End Sub
    18. #End Region
    19. #Region "ICommand Members"
    20. Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute
    21. Return If(_canExecute Is Nothing, True, _canExecute(parameter))
    22. End Function
    23. Public Sub RaiseCanExecuteChanged()
    24. RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
    25. End Sub
    26. Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute
    27. _execute(parameter)
    28. End Sub
    29. #End Region
    30. End Class


    Nur eben, wenn sich die lib jetzt doch als buggy erweist
    Glaub ich nicht. Ich kann nunmal kein Englisch, außer dem, was man durch die Klassen- und Methodennamen so mitkriegt. Ich mach da iwas grundlegend falsch bei der Anwendung von Galasoft, weil ich deren Einführung nicht richtig versteh. Im Moment komm ich aber eigentlich gut mit dem selbst zusammengestoppelten Kram (Relaycommand, Listcollectionview, und deinem angepassten MainModel) zurecht und ich versteh es obendrein auch noch :thumbsup:
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup: