none
Zwei Comboboxen mit gleichem Binding unterschiedlich sortieren RRS feed

  • Frage

  • Hallo,

    ich bezeichne mich als Anfänger in C# und WPF und habe ein Problem an dem ich nicht weiter weiss. Ich habe eine CSV-Datei in eine Datatable eingelesen. Die Table enthält u.a. Postleitzahlen und Ortsnamen der Firmen Standorte. Nun möchte ich in meiner Oberfläche 2 Comboboxen hinzufügen wo ich in der einen Combobox die Postleitzahlen sortiert habe und in der anderen Combobox die Standorte sortiert, so das der Anwender entweder nach PLZ oder nach Standort auswählen kann.

    Mit folgendem Code habe ich es versucht, die Sortierung funktioniert, ich kann den Standort sowohl nach PLZ oder Ortsnamen auswählen allerdings verhalten sich die Comboboxen dann etwas merkwürdig. Wenn die Dropdown-Liste der Combobox aufklappt wird das Item wo ich mit der Maus drüber bin nicht mehr highlighted. Ist das ein Bug in der WPF Combobox oder sollte man das ganze anders implementieren ??

     

    private void comboBox_Ort_GotFocus(object sender, RoutedEventArgs e)
        {
          ICollectionView cv = CollectionViewSource.GetDefaultView(comboBox_Ort.ItemsSource);
          cv.SortDescriptions.Clear();
          cv.SortDescriptions.Add(new SortDescription("Ort", ListSortDirection.Ascending));
          cv.Refresh();
        }
    
    private void comboBox_PLZ_GotFocus(object sender, RoutedEventArgs e)
        {
          ICollectionView cv = CollectionViewSource.GetDefaultView(comboBox_PLZ.ItemsSource);
          cv.SortDescriptions.Clear();
          cv.SortDescriptions.Add(new SortDescription("PLZ", ListSortDirection.Ascending));
          cv.Refresh();
        }
    

    <ComboBox Name="comboBox_PLZ" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="PLZ" ItemsSource="{Binding sko}" IsReadOnly="True" GotFocus="comboBox_PLZ_GotFocus" />
    <ComboBox Name="comboBox_Ort" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Ort" ItemsSource="{Binding sko}" IsReadOnly="True" GotFocus="comboBox_Ort_GotFocus" />
    

    Gruss, André

    Sonntag, 5. September 2010 08:15

Antworten

  • Hallo Peter,

    nachdem ja beide Comboboxen in deiner Lösung nicht synchronisiert sind habe ich deinen Code um einen Konstruktor in der ViewModel Klasse ergänzt:

    Public Sub New()
     AddHandler cvsOrt.View.CurrentChanged, Sub()
      cvsPLZ.View.MoveCurrentTo(cvsOrt.View.CurrentItem())
     End Sub
    
     AddHandler cvsPLZ.View.CurrentChanged, Sub()
      cvsOrt.View.MoveCurrentTo(cvsPLZ.View.CurrentItem())
     End Sub
    End Sub
    

    Es funktioniert einwandfrei, ob das allerdings die "richtige" Lösung ist weiss ich nicht, dazu habe ich zu wenig .NET Erfahrung.

    Vielen Dank für deinen Code.

    Gruss, André

    • Als Antwort vorgeschlagen Frank Dzaebel Montag, 6. September 2010 09:19
    • Als Antwort markiert Andre Steden Montag, 6. September 2010 14:41
    Montag, 6. September 2010 09:03

Alle Antworten

  • Hi André,
    die Liste der ComboBox wird nicht in der ComboBox gehalten, sondern bei jedem Bedarf (z.B. Aufklappen, Refresh) werden die Elemente aus der Datenquelle für die Anzeige gelesen. Die gleiche Datenquelle kannst du zur gleichen Zeit nicht unterschiedlich sortieren. Schalte zwischen Datenquelle und ComboBox eine Sicht, die das Sortieren ermöglicht. Hier mal eine Demo mit VB10:
     
     

    <Window x:Class="Window1"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="Window1"
       Height="500" Width="700"
       xmlns:my="clr-namespace:WpfApplication1">
     <Window.Resources>
      <my:ViewModel x:Key="vm"/>
     </Window.Resources>
     <Canvas DataContext="{Binding Source={StaticResource vm}}">
      <ComboBox Width="150" ItemsSource="{Binding View1}" DisplayMemberPath="Ort" />
      <ComboBox Canvas.Left="160" Width="200" ItemsSource="{Binding View2}" DisplayMemberPath="PLZ" />
     </Canvas>
    </Window>
    

    Dazu der ViewModel:

    Imports System.ComponentModel
    Imports System.Data
    Imports System.Collections.ObjectModel
    
    Public Class ViewModel
     Implements INotifyPropertyChanged
    
     Private m As New Model
    
     Private col As New ObservableCollection(Of Stadt)(From e In m.Data.AsEnumerable Select New Stadt With {.Ort = e!Ort, .PLZ = e!PLZ})
    
     Private cvsOrt As New CollectionViewSource With {.Source = col}
     Private cvsPLZ As New CollectionViewSource With {.Source = col}
    
    
     Public ReadOnly Property View1() As ICollectionView
      Get
       With cvsOrt
        With .View.SortDescriptions
         .Clear()
         .Add(New SortDescription("Ort", ListSortDirection.Ascending))
        End With
        Return .View
       End With
      End Get
     End Property
    
     Public ReadOnly Property View2() As ICollectionView
      Get
       With cvsPLZ
        With .View.SortDescriptions
         .Clear()
         .Add(New SortDescription("PLZ", ListSortDirection.Ascending))
        End With
        Return .View
       End With
      End Get
     End Property
    
    
     Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    End Class
    
    Public Class Model
    
     Private dt As New DataTable
     Private rnd As New Random
    
     Public Sub New()
      With dt
       With .Columns
        .Add("ID", GetType(Integer))
        .Add("PLZ", GetType(String))
        .Add("Ort", GetType(String))
       End With
       For i = 1 To 100
        Dim r = .NewRow
        r!ID = i
        r!PLZ = String.Format("{0:00000}", rnd.Next(1000, 99999))
        r!Ort = "Ort " & i.ToString
        .Rows.Add(r)
       Next
      End With
     End Sub
    
     Public ReadOnly Property Data() As DataTable
      Get
       Return Me.dt
      End Get
     End Property
    
    End Class
    
    Public Class Stadt
     Public Property PLZ As String
     Public Property Ort As String
    End Class
    

    --
    Viele Gruesse
    Peter

    • Als Antwort vorgeschlagen Frank Dzaebel Montag, 6. September 2010 09:20
    Sonntag, 5. September 2010 11:13
  • Hallo Peter,

    vielen Dank für deine Antwort.  Mir war schon klar das die Datenquelle nicht in der Combobox gespeichert wird, deshalb hatte ich ja versucht im OnFocus Event der Comboboxen jeweils umzusortieren, daraufhin verhalten sich die Comboboxen ja etwas eigenartig. Wenn ich allerdings 2 Buttons anlege in denen ich die CollectionViewSource umsortiere funktioniert alles einwandfrei. Nur im OnFocus Event der Combobox geht es nicht richtig.

    Ich habe vorhin dein Beispiel ausprobiert. Das ist nicht ganz so wie es funktionieren sollte. Wenn ich bei deinem Code in der ersten ComboBox (Ort) einen Ort auswähle ist die PLZ Combobox dazu nicht synchronisiert und andersrum genauso.

    d.h. ich wollte bei Auswahl der PLZ das in der Combobox Ort auch der passende Ort angezeigt wird. Wähle ich einen Ort aus dann soll in der PLZ Combobox die passende Postleitzahl erscheinen.

     

    Gruss André

     

    Sonntag, 5. September 2010 17:17
  • Hallo Peter,

    nachdem ja beide Comboboxen in deiner Lösung nicht synchronisiert sind habe ich deinen Code um einen Konstruktor in der ViewModel Klasse ergänzt:

    Public Sub New()
     AddHandler cvsOrt.View.CurrentChanged, Sub()
      cvsPLZ.View.MoveCurrentTo(cvsOrt.View.CurrentItem())
     End Sub
    
     AddHandler cvsPLZ.View.CurrentChanged, Sub()
      cvsOrt.View.MoveCurrentTo(cvsPLZ.View.CurrentItem())
     End Sub
    End Sub
    

    Es funktioniert einwandfrei, ob das allerdings die "richtige" Lösung ist weiss ich nicht, dazu habe ich zu wenig .NET Erfahrung.

    Vielen Dank für deinen Code.

    Gruss, André

    • Als Antwort vorgeschlagen Frank Dzaebel Montag, 6. September 2010 09:19
    • Als Antwort markiert Andre Steden Montag, 6. September 2010 14:41
    Montag, 6. September 2010 09:03