Earlgray
Earlgray

Reputation: 647

LongListSelector doesn't show items

I implement LongListSelector because I want to group items. But this LongListSelector dont show any item when I run it.

This is my XML source:

<?xml version="1.0" encoding="utf-8"?>
<Tasks>
  <Task>
    <Name>first task</Name>
    <DueDate>05/03/2013 00:00:00</DueDate>
    <Created>03/27/2013 01:24:08</Created>
  </Task>
  <Task>
    <Name>second task</Name>
    <DueDate>05/17/2013 00:00:00</DueDate>
    <Created>03/27/2013 01:24:19</Created>
  </Task>
  <Task>
    <Name>third task</Name>
    <DueDate>05/17/2013 00:00:00</DueDate>
    <Created>03/27/2013 01:24:38</Created>
  </Task>
</Tasks>

My XAML code:

<toolkit:LongListSelector Background="Transparent" ItemsSource="{Binding TasksByDueDate}">
    <toolkit:LongListSelector.GroupHeaderTemplate>
        <DataTemplate>
            <Border Background="Transparent">
                <Border Background="{StaticResource PhoneAccentBrush}" Width="475" Height="35" HorizontalAlignment="Left">
                    <TextBlock Text="{Binding Key}" 
                           Foreground="{StaticResource PhoneForegroundBrush}" 
                           Style="{StaticResource PhoneTextGroupHeaderStyle}"
                           VerticalAlignment="Bottom"/>
                </Border>
            </Border>
        </DataTemplate>
    </toolkit:LongListSelector.GroupHeaderTemplate>
    <toolkit:LongListSelector.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="0,0,0,17" Width="432" Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Width="345"/>
            </StackPanel>
        </DataTemplate>
    </toolkit:LongListSelector.ItemTemplate>
</toolkit:LongListSelector>

MainViewModel.cs:

public class MainViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Task> Tasks { get; private set; }

    public IEnumerable<Group<string, Task>> TasksByDueDate { get; private set; }

    public MainViewModel()
    {
        this.Tasks = new ObservableCollection<Task>();
        this.Projects = new ObservableCollection<Project>();
        this.Contexts = new ObservableCollection<Context>();
    }

    public bool IsDataLoaded { get; private set; }

    public void LoadPlannedData()
    {
        try
        {
            Tasks.Clear();

            var file = IsolatedStorageFile.GetUserStoreForApplication();
            XElement xElem;

            using (IsolatedStorageFileStream read = file.OpenFile("tasks.xml", FileMode.Open))
            {
                xElem = XElement.Load(read);
            }

            var tasks = from task in xElem.Elements("Task")
                        orderby (DateTime)task.Element("Created") descending
                        select task;

            foreach (XElement xElemItem in tasks)
            {
                Tasks.Add(new Task
                {
                    Name = xElemItem.Element("Name").Value.ToString(),
                    DueDate = xElemItem.Element("DueDate").Value.ToString(),
                    Created = xElemItem.Element("Created").Value.ToString()
                });
            }

            TasksByDueDate = from c in Tasks 
                             group c by c.DueDate into n
                             select new Group<string, Task>(n);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }

        this.IsDataLoaded = true;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Group.cs:

public class Group<TKey, TElement> : IGrouping<TKey, TElement>
{
    private readonly IGrouping<TKey, TElement> grouping;

    public Group(IGrouping<TKey, TElement> unit)
    {
        grouping = unit;
    }

    public TKey Key
    {
        get { return grouping.Key; }
    }

    public IEnumerator<TElement> GetEnumerator()
    {
        return grouping.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return grouping.GetEnumerator();
    }
}

If I show ListBox of Task then everything is Displayed well. But if I display grouped items then, no item is displayed.

Aplication runs wel (no crash) only items in LongListSelector missing.

What am I doing wrong?

Upvotes: 0

Views: 1824

Answers (1)

PJ .
PJ .

Reputation: 61

I spent 2-3 days chasing down this same issue and it was a nightmare. I believe the answer is that the ItemsSource data format needs to be IList. Unfortunately that won't really help you much, but here are two classes that I've created that ... well they work at least.

My StringKeyGroup allows full text group names, whilst the AlphaKeyGroup alphabetises the list.

StringKeyGroup class

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;

namespace LongListSelectorDemo.Model
{
    public class StringKeyGroup<T> : ObservableCollection<T>
    {
        public delegate string GetKeyDelegate(T item);
        public string Key { get; private set; }
        public StringKeyGroup(string key)
        {
            Key = key;
        }
        public static ObservableCollection<StringKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
        {
            var list = new ObservableCollection<StringKeyGroup<T>>();

            foreach (var item in items)
            {
                var index = -1;
                for (var i = 0; i < list.Count; i++)
                {
                    if (list[i].Key.Equals(getKey(item)))
                    {
                        index = i;
                        break;
                    }
                }
                if (index == -1)
                {
                    list.Add(new StringKeyGroup<T>(getKey(item)));
                    index = list.Count - 1;
                }
                if (index >= 0 && index < list.Count)
                {
                    list[index].Add(item);
                }
            }

            if (sort)
            {
                foreach (var group in list)
                {
                    group.ToList().Sort((c0, c1) => ci.CompareInfo.Compare(getKey(c0), getKey(c1)));
                }
            }

            return list;
        }
    }
}

AlphaKeyGroup class

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using Microsoft.Phone.Globalization;

namespace LongListSelectorDemo.Model
{
    public class AlphaKeyGroup<T> : ObservableCollection<T>
    {
        /// <summary>
        /// The delegate that is used to get the key information.
        /// </summary>
        /// <param name="item">An object of type T</param>
        /// <returns>The key value to use for this object</returns>
        public delegate string GetKeyDelegate(T item);

        /// <summary>
        /// The Key of this group.
        /// </summary>
        public string Key { get; private set; }

        /// <summary>
        /// Public constructor.
        /// </summary>
        /// <param name="key">The key for this group.</param>
        public AlphaKeyGroup(string key)
        {
            Key = key;
        }

        /// <summary>
        /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
        /// </summary>
        /// <param name="slg">The </param>
        /// <returns>Theitems source for a LongListSelector</returns>
        private static ObservableCollection<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
        {
            return new ObservableCollection<AlphaKeyGroup<T>>(slg.GroupDisplayNames.Select(key => new AlphaKeyGroup<T>(key)).ToList());
        }

        /// <summary>
        /// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
        /// </summary>
        /// <param name="items">The items to place in the groups.</param>
        /// <param name="ci">The CultureInfo to group and sort by.</param>
        /// <param name="getKey">A delegate to get the key from an item.</param>
        /// <param name="sort">Will sort the data if true.</param>
        /// <returns>An items source for a LongListSelector</returns>
        public static ObservableCollection<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
        {
            var slg = new SortedLocaleGrouping(ci);
            var list = CreateGroups(slg);

            foreach (var item in items)
            {
                var index = 0;
                if (slg.SupportsPhonetics)
                {
                    //check if your database has yomi string for item
                    //if it does not, then do you want to generate Yomi or ask the user for this item.
                    //index = slg.GetGroupIndex(getKey(Yomiof(item)));
                }
                else
                {
                    index = slg.GetGroupIndex(getKey(item));
                }
                if (index >= 0 && index < list.Count)
                {
                    list[index].Add(item);
                }
            }

            if (sort)
            {
                foreach (var group in list)
                {
                    group.ToList().Sort((c0, c1) => ci.CompareInfo.Compare(getKey(c0), getKey(c1)));
                }
            }

            return list;
        }
    }
}

Example usage, just swap the class name between StringKeyGroup and AlphaKeyGroup to see the difference:

XAML

<phone:PhoneApplicationPage
    x:Class="LongListSelectorDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <phone:LongListSelector x:Name="GroupedList" IsGroupingEnabled="True" HideEmptyGroups="True">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" Padding="{StaticResource PhoneTouchTargetOverhang}" 
            FontSize="{StaticResource PhoneFontSizeMediumLarge}" />
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
                <phone:LongListSelector.GroupHeaderTemplate>
                    <DataTemplate>
                        <Border Background="{StaticResource PhoneAccentBrush}" 
            Padding="{StaticResource PhoneTouchTargetOverhang}">
                            <TextBlock Text="{Binding Key}" Style="{StaticResource PhoneTextGroupHeaderStyle}"/>
                        </Border>
                    </DataTemplate>
                </phone:LongListSelector.GroupHeaderTemplate>
            </phone:LongListSelector>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

XAML.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;
using LongListSelectorDemo.Model;
using Microsoft.Phone.Controls;

namespace LongListSelectorDemo
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Sample code to localize the ApplicationBar
            //BuildLocalizedApplicationBar();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            if (GroupedList.ItemsSource == null)
            {
                var foodItems = new ObservableCollection<FoodItem>();

                /*---Make burger items---*/
                foodItems.Add(new FoodItem("Hamburger", "Burgers"));
                foodItems.Add(new FoodItem("Chicken burger", "Burgers"));
                foodItems.Add(new FoodItem("Turkey burger", "Burgers"));
                foodItems.Add(new FoodItem("Black bean burger", "Burgers"));

                /*---Make fryer items---*/
                foodItems.Add(new FoodItem("Fries", "Fryer"));
                foodItems.Add(new FoodItem("Onion rings", "Fryer"));
                foodItems.Add(new FoodItem("Tater tots", "Fryer"));
                foodItems.Add(new FoodItem("Mozzarella sticks", "Fryer"));

                /*---Make fish items---*/
                foodItems.Add(new FoodItem("Salmon", "Fish"));
                foodItems.Add(new FoodItem("Rainbow trout", "Fish"));
                foodItems.Add(new FoodItem("Grilled tilapia", "Fish"));

                GroupedList.ItemsSource = GroupedItems(foodItems);
            }
        }

        public ObservableCollection<StringKeyGroup<FoodItem>> GroupedItems(IEnumerable<FoodItem> source)
        {
            return StringKeyGroup<FoodItem>.CreateGroups(source,
    System.Threading.Thread.CurrentThread.CurrentUICulture, s => s.GroupName, true);
        }
    }
}

Here is the FoodItem class:

namespace LongListSelectorDemo.Model
{
    public class FoodItem
    {
        public FoodItem(string name, string groupName)
        {
            Name = name;
            GroupName = groupName;
        }
        public string Name { get; private set; }
        public string GroupName { get; private set; }
    }
}

Upvotes: 1

Related Questions