Question

I wanted to create a LongListSelector control in which values are grouped into many categories. Each item has got these properties:

Public Class SideItem
  Private _Title As String
  Public Property Title As String
    Get
        Return _Title
    End Get
    Set(value As String)
        _Title = value
    End Set
  End Property

  Private _Icon As System.Windows.Shapes.Path
  Public Property Icon As System.Windows.Shapes.Path
    Get
        Return _Icon
    End Get
    Set(value As System.Windows.Shapes.Path)
        _Icon = value
    End Set
  End Property

  Private _Category As String
  Public Property Category As String
    Get
        Return _Category
    End Get
    Set(value As String)
        _Category = value
    End Set
  End Property

  Private _NavigationUri As Uri
  Public Property NavigationUri As Uri
    Get
        Return _NavigationUri
    End Get
    Set(value As Uri)
        _NavigationUri = value
    End Set
  End Property
End Class

I'd like to group a list of SideItem depending on the value of Category property. I looked into several examples but I didn't manage to do it. This is my latest attempt (of several ones)

Me.Items = (From data In L
             Group data By Key = New With {Key data.Category} Into Group
             Select New SideItem With {
                 .Category = Key.Category, _
                 .Title = Group.Select(Function(itm As SideItem) itm.Title), _
                 .Icon = Group.Select(Function(itm As SideItem) itm.Icon), _
                 .NavigationUri = Group.Select(Function(itm As SideItem) itm.NavigationUri)
             }).OfType(Of SideItem)()

UPDATE: SOLUTION

I used the code you can find in verdesrobert's answer voted as best, but I edited the AlphaKeyGroup class in order to fit my needs.

Public Class AlphaKeyGroup(Of T)
Inherits List(Of T)
Public Delegate Function GetKeyDelegate(item As T) As String

Public Property Key() As String
    Get
        Return m_Key
    End Get
    Private Set(value As String)
        m_Key = value
    End Set
End Property
Private m_Key As String

Public Sub New(key__1 As String)
    Key = key__1
End Sub
Private Shared Function CreateGroups(slg As List(Of String)) As List(Of AlphaKeyGroup(Of T))
    Dim list As New List(Of AlphaKeyGroup(Of T))()

    For Each key As String In slg
        list.Add(New AlphaKeyGroup(Of T)(key))
    Next
    Return list
End Function

Public Shared Function CreateGroups(items As IEnumerable(Of T), ci As CultureInfo, getKey As GetKeyDelegate, sort As Boolean) As List(Of AlphaKeyGroup(Of T))
    Dim headerList As New List(Of String)
    For Each header As T In items
        headerList.Add(getKey(header))
    Next
    Dim list As List(Of AlphaKeyGroup(Of T)) = CreateGroups(headerList)

    For Each item As T In items
        list(list.IndexOf(list.Where(Function(I As AlphaKeyGroup(Of T)) I.Key = getKey(item)).First)).Add(item)
    Next

    If sort Then
        For Each group As AlphaKeyGroup(Of T) In list
            group.Sort(Function(c0, c1)
                           Return ci.CompareInfo.Compare(getKey(c0), getKey(c1))
                       End Function)
        Next
    End If
    Return list
End Function

End Class

Was it helpful?

Solution

First you need a class that provides a grouped list structure:

    Public Class AlphaKeyGroup(Of T)
    Inherits List(Of T)
    Public Delegate Function GetKeyDelegate(item As T) As String

    Public Property Key() As String
        Get
            Return m_Key
        End Get
        Private Set
            m_Key = Value
        End Set
    End Property
    Private m_Key As String

    Public Sub New(key__1 As String)
        Key = key__1
    End Sub
    Private Shared Function CreateGroups(slg As SortedLocaleGrouping) As List(Of AlphaKeyGroup(Of T))
        Dim list As New List(Of AlphaKeyGroup(Of T))()

        For Each key As String In slg.GroupDisplayNames
            list.Add(New AlphaKeyGroup(Of T)(key))
        Next
        Return list
    End Function

    Public Shared Function CreateGroups(items As IEnumerable(Of T), ci As CultureInfo, getKey As GetKeyDelegate, sort As Boolean) As List(Of AlphaKeyGroup(Of T))
        Dim slg As New SortedLocaleGrouping(ci)
        Dim list As List(Of AlphaKeyGroup(Of T)) = CreateGroups(slg)

        For Each item As T In items
            Dim index As Integer = 0
            index = slg.GetGroupIndex(getKey(item))
            If index >= 0 AndAlso index < list.Count Then
                list(index).Add(item)
            End If
        Next

        If sort Then
            For Each group As AlphaKeyGroup(Of T) In list
                group.Sort(Function(c0, c1) 
                Return ci.CompareInfo.Compare(getKey(c0), getKey(c1)) 
                          End Function)
            Next
        End If
        Return list
    End Function
End Class

Using your class SideItem you should then create a list of SideItem:

// Your code to provide the list of items like this:
Dim source As New List(Of SideItem)()
//add data to the list or skip the creation and provide your data 

Then group the list like this:

List<AlphaKeyGroup<SideItem>> DataSource = AlphaKeyGroup<SideItem>.CreateGroups(source, 
            System.Threading.Thread.CurrentThread.CurrentUICulture,
            (SideItem s) => { return s.Category; }, true);

Bind to the LongListSelector ItemsSource:

Me.ItemsSource = DataSource;

LongListSelector XAML:

<phone:LongListSelector
    x:Name="Me"
    JumpListStyle="{StaticResource SideItemJumpListStyle}"
    Background="Transparent"
    GroupHeaderTemplate="{StaticResource SideItemGroupHeaderTemplate}"
    ItemTemplate="{StaticResource SideItemItemTemplate}"
    LayoutMode="List"
    IsGroupingEnabled="true"
    HideEmptyGroups ="true"/>

ItemTemplate XAML:

<DataTemplate x:Key="SideItemItemTemplate">
   <StackPanel VerticalAlignment="Top">
      <TextBlock FontWeight="Bold"  Text="{Binding Title}" />
   </StackPanel>
</DataTemplate>

GroupHeaderTemplate XAML:

<DataTemplate x:Key="SideItemGroupHeaderTemplate">
   <Border Background="Transparent" Padding="5">
      <Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62" 
         Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
         <TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6" 
            FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
      </Border>
   </Border>
</DataTemplate>

JumpListStyle XAML:

    <phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
    <phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
    <Style x:Key="SideItemJumpListStyle" TargetType="phone:LongListSelector">
        <Setter Property="GridCellSize"  Value="113,113"/>
        <Setter Property="LayoutMode" Value="Grid" />
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
                        <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6" 
           Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>

This should be enough.

Answer based on http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj244365(v=vs.105).aspx

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top