Silverlight Listbox mit Mehrfachauswahl

Was bei ASP.NET sehr einfach war, ist bei Silverlight mit großen Mühen verbunden. Zwar unterstützt das Silverlight Datagrid eine Mehrfachauswahl per Attribut, aber die Listbox nicht. Ich zeige im folgenden Beispiel wie man mit Checkboxen dem Benutzer die Auswahl erlauben kann. Anschliessend sollen diese Checkboxen durchlaufen werden.

Hört sich einfach an, ist es aber nicht, da der Inhalt des Datatemplates nicht angesprochen werden kann. Auch Tricks per Findname oder x:Namer funtkionieren nicht. Eine unschöne Möglichkeit ist, mit Hilfe des visualtreehelpers komplett die Seite zu durchlaufen. Das ist sehr unhandlich da eine checkbox schon mindestens aus zwei Controls besteht, einem Textblock und einem  Rectangle.

Meine Lösung verwendet zwei-Wege Datenbindung. Zuerst kommt der mühsame Teil eine Klasse zu schreiben. Diese muss für die Checkbox ein zusätzliches Property aufweisen und das Interface für die Zwei Wege Bindung implementieren.

Imports System.ComponentModel
Imports System.Collections.ObjectModel
Public Class Listboxdaten
    Implements INotifyPropertyChanged
    Private _checked As Boolean
    Public Property checked() As Boolean
        Get
            Return _checked
        End Get
        Set(ByVal value As Boolean)
            _checked = value
            OnPropertyChanged("checked")
        End Set
    End Property

    Private _daten As String
    Public Property daten() As String
        Get
            Return _daten
        End Get
        Set(ByVal value As String)
            _daten = value
            OnPropertyChanged("daten")
        End Set
    End Property
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    Protected Sub OnPropertyChanged(ByVal name As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
    End Sub
End Class

Dann noch XAML und die zwei Wege Datenbindung in der Checkbox. Mit der Binding Syntax müssten Sie sich auskennen.

<ListBox x:Name="lstFields" SelectionChanged="lstFields_SelectionChanged" >
     <ListBox.ItemTemplate>
                <DataTemplate>
              <StackPanel Orientation="Horizontal" x:Name="stack1">
                   <CheckBox x:Name="chkFields" IsChecked="{Binding checked, Mode=TwoWay}"></CheckBox>
                      <TextBlock Text="{Binding daten}"></TextBlock>
                </StackPanel>
         </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
<Button x:Name="Button1" Width="30" Height="20" Click="Button1_Click"></Button>

Im Loaded Event werden dann die Einträge in der Listbox vom passenden Typ erzeugt

Private Sub page17_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        lstFields.Items.Add(New Listboxdaten With {.checked = True, .daten = "eins"})
        lstFields.Items.Add(New Listboxdaten With {.checked = True, .daten = "zwei"})
        lstFields.Items.Add(New Listboxdaten With {.checked = True, .daten = "drei"})

Im Button Click Handler kann dann auf das ListboxItem zugegriffen werden und nach einem Typ Cast die  checked Eigenschaft gelesen werden.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        For Each i In lstFields.Items
            If CType(i, Listboxdaten).checked Then
                MessageBox.Show("checked")
            End If
        Next
End Sub

Natürlich gibts auch andere Lösungen zb mit einer ObservableCollection. Aber einfacher geht es meiner Ansicht nach nicht mehr.

Kommentar schreiben