locked
ObservableCollection(Of T) sortieren --- Wie? RRS feed

  • Frage

  • Hallo,

    ich habe eine einfache Klasse Person für Datenobjekte, die nur die String-Property .Name offenlegt. Aus den Objekten dieser Klasse bilde ich eine ObservableCollection(Of Person) PersonOC, die ich als ItemsSource an eine ListBox binde. 

    Wie kann ich meine PersonOC, also meine ObservableCollection (Of Person), sortieren?

    Bin für jede Hilfe dankbar. Am besten mit einem Code-Beispiel in VB.NET.

    Beste Grüße,
    M.
    Samstag, 6. Februar 2010 05:49

Antworten

Alle Antworten

  • Hi Community,

    ich habe die Lösung mal wieder selbst gefunden und sie in meinem Blog veröffentlicht:

    http://blogs.windowsclient.net/silverlaw/archive/2010/02/06/short-and-simple-how-to-sort-an-observablecollection-of-t-in-silverlight-3.aspx

    Beste Grüße,
    M.
    Samstag, 6. Februar 2010 14:41
  • Die von die dargestellte Lösung ist nicht im Sinne der Möglichkeiten des Frameworks und damit auch nicht optimal, besonders für größere Datenmenge werden unbegründet viel Ressourcen benötigt. Für solche Zwecke (Sortieren, Gruppieren) gibt es die CollectionViewSource-Klasse, die interen einen Index für den schnellen Zugriff auf die Basisdatemenge ermöglicht, ohne dass die Basisdatenmenge umgruppiert werden muss (ähnlich DataView-Klasse für ein DataTable-Objekt in ADO.NET). Eine Lösung per Code könnte so aussehen:

    Imports System.Collections.ObjectModel
    Imports System.Windows.Data
    Imports System.ComponentModel
    
    Partial Public Class SilverlightControl1
      Inherits UserControl
    
      Public Sub New()
        InitializeComponent()
      End Sub
    
      Private DebitorOC As New ObservableCollection(Of Debitor)
      Private cvs As New CollectionViewSource With {.Source = DebitorOC}
    
      Private Sub SilverlightControl1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        With DebitorOC
          .Add(New Debitor("Zacharias"))
          .Add(New Debitor("Adam"))
          .Add(New Debitor("Junghans"))
        End With
        With Me.lbDebitors
          .ItemsSource = cvs.View
          .DisplayMemberPath = "Name"
        End With
      End Sub
    
      Private Sub Sort_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        cvs.SortDescriptions.Add(New SortDescription("Name", ListSortDirection.Ascending))
      End Sub
    
    End Class
    --
    Peter
    Samstag, 6. Februar 2010 19:52
  • Hallo Peter,

    vielen Dank für Deine Antwort. Aber Dein Code funktioniert bei mir leider nicht.

      Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

     

        With DebitorOC

          .Add(New Debitor("Zacharias"))

          .Add(New Debitor("Adam"))

          .Add(New Debitor("Junghans"))

        End With

     

        With Me.lbDebitors

          .ItemsSource = cvs.View '<----- Nach dieser Zuweisung hat Me.lbDebitor.ItemsSource den Wert Nothing

          .DisplayMemberPath = "Name"

        End With

     

      End Sub



    Ich bevorzuge jedenfalls die Konvention. Deswegen: Wie sieht Dein XAML aus?

    Beste Grüße,
    M.
    Sonntag, 7. Februar 2010 06:22
  • Wenn bei dir cvs.View = Nothing ist, dann fehlt die Source-Zuweisung. Indeinem Code ist sie auch nicht dargestellt (s. mein Code).

    Das ist mein XML dazu:

    <UserControl x:Class="SilverlightApplication1.SilverlightControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="400" Height="300">
      <StackPanel>
        <Button Content="Sortieren" Click="Sort_Click"></Button>
        <ListBox Name="lbDebitors"></ListBox>
      </StackPanel>
    </UserControl>

    Wenn du willst, kann ich ein vollständiges Projekt hochladen.

    --
    Peter
    Sonntag, 7. Februar 2010 07:19
  • Hallo Peter,

    ein vollständiges Projekt wäre sehr gut.

    Ich habe mal eben mein Beispiel-Project als Download in meinen Blog-Artikel bereitgestellt. Vielleicht kannst Du ja dieses konkrete Beispiel nehmen um eine Lösung mit CollectionView zu demonstrieren.

    Viele Grüße,
    M.
    Sonntag, 7. Februar 2010 09:15
  • Mein Projekt besteht nur aus dem geposteten XAML und dem CodeBehind dazu. Damit ist es vollständig.

    Ein Projekt werde ich auf meiner Homepage veröffentlichen. Jetzt ist es aber schon spät (hier in Neuseeland) und ich werde morgen Abend weiter daran arbeiten, da ich auch die Varianten mit Ressourcenbindung noch austesten muss.

    --
    Peter

    Sonntag, 7. Februar 2010 09:27
  • So funktioniert es jetzt bei mir:

    Imports System.Collections.ObjectModel

    Imports System.Windows.Data

    Imports System.ComponentModel

     

    Partial Public Class MainPage

      Inherits UserControl

     

      Public Sub New()

        InitializeComponent()

      End Sub

     

      Private DebitorOC As New ObservableCollection(Of Debitor)

      Private DebitorCVS As New CollectionViewSource With {.Source = DebitorOC}

     

      Private Sub MainPage_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        With DebitorOC

          .Add(New Debitor("Hans"))

          .Add(New Debitor("Adam"))

          .Add(New Debitor("Dieter"))

          .Add(New Debitor("Bernd"))

        End With

        With lbDebitors

          .ItemsSource = DebitorCVS.View

        End With

     

      End Sub

     

      Private Sub btAdd_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btAdd.Click

        DebitorOC.Add(New Debitor("Fritz"))

      End Sub

     

      Private Sub btRemove_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btRemove.Click

        Dim _debitor As Debitor = TryCast(lbDebitors.SelectedItem, Debitor)

        If _debitor Is Nothing Then

          Return

        End If

        If DebitorOC.Contains(_debitor) Then

          DebitorOC.Remove(_debitor)

        End If

      End Sub

     

      Private Sub btSort_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btSort.Click

        DebitorCVS.SortDescriptions.Add(New SortDescription("Name", ListSortDirection.Ascending))

      End Sub

    End Class

    <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

                x:Class="ObservableCollectionViewSourceBindingLab.MainPage"

                Width="640"

                Height="480"

                mc:Ignorable="d"

                FontFamily="Verdana"

                FontSize="12">

     

     <Grid x:Name="LayoutRoot"

          Background="White">

      <Grid.RowDefinitions>

       <RowDefinition Height="0.158*" />

       <RowDefinition Height="0.538*" />

       <RowDefinition Height="0.088*" />

       <RowDefinition Height="0.085*" />

       <RowDefinition Height="0.131*" />

      </Grid.RowDefinitions>

      <!-- ListBox -->

      <ListBox x:Name="lbDebitors"

              Margin="20,0"

              Background="Brown"

              Grid.Row="1">

       <ListBox.ItemTemplate>

        <DataTemplate>

         <TextBlock Foreground="FloralWhite"

                   Margin="3"

                   Text="{Binding Name}" />

        </DataTemplate>

       </ListBox.ItemTemplate>

      </ListBox>

      <Grid Margin="20,0"

           Grid.Row="2">

       <Grid.ColumnDefinitions>

        <ColumnDefinition Width="0.49*" />

        <ColumnDefinition Width="0.51*" />

       </Grid.ColumnDefinitions>

       <Button x:Name="btAdd"

              HorizontalAlignment="Right"

              Margin="0,0,2,0"

              Width="80"

              Content="Add"

              Height="26"

              VerticalAlignment="Center" />

       <Button x:Name="btRemove"

              HorizontalAlignment="Left"

              Margin="2,0,0,0"

              Width="80"

              Content="Remove"

              Grid.Column="1"

              Height="26" />

      </Grid>

      <Button x:Name="btSort"

             HorizontalAlignment="Center"

             VerticalAlignment="Top"

             Width="80"

             Content="Sort"

             Grid.Row="3"

             Height="26"

             Margin="-7,0,0,0" />

     </Grid>

    </UserControl>

     

    Diese Lösung mit Deiner Hilfe ist wirklich besser. Eine Änderung war erforderlich. Da ich ein ItemTemplate in meiner Listbox benutze mußte ich die Zuweisung Displaymemberpath = "Name" entfernen. Damit läuft es einwandfrei. Bin trotzdem gespannt auf Deinen Beispielcode.

    Beste Grüße nach Neuseeland.

    M.

    Sonntag, 7. Februar 2010 16:07
  • ich habe die Demo hochgeladen, zu finden unter:

    <Tipps und Tricks - informtools - Tipp 399>
    http://www.informtools.de/kb.aspx?id=399

    --
    Peter
    • Als Antwort vorgeschlagen Peter Fleischer Donnerstag, 11. Februar 2010 07:41
    Donnerstag, 11. Februar 2010 07:40