VictorFleur
VictorFleur

Reputation: 1

longlistselector items not added correctly in groups

I'm trying to build a LongListSelector (toolkit) using an ObservableCollection. I followed this tutorial and everything works fine with sample data. However, once I try to populate the list with data downloaded from the Internet, it becomes a mess! There are empty groups, items not placed correctly and few things are sorted alphabetically.

I'm using this code to create empty groups for all the letters:

private static readonly string Groups = "#abcdefghijklmnopqrstuvwxyz";  

/* ... other things ... */ 

List<Country> empty = new List<Country>();  
foreach (char c in Groups)  
{  
    Group<Country> emptyGroup = new Group<Country>(c.ToString(), empty);  
    App.Colst.cityByCountryList.Add(emptyGroup);  
} 

Then I created a WebClient that downloads a xml file from the Internet and the analyze it, adding items to the groups in this way:

string id = dreader.GetAttribute("id");  
string name = dreader.GetAttribute("name_it");  
string citynumber = dreader.GetAttribute("citiesNumber");  

if (id != null && id != "")  
{  
    Group<Country> firstGroup = App.Colst.cityByCountryList[Groups.IndexOf(name.Substring(0, 1).ToLower())];  
    Country newCountry = new Country() { Lett = name.Substring(0, 1).ToLower(), Name = name };  
    firstGroup.Add(newCountry);  
} 

and this is the result(I'm a new user and I can't upload an image... so I'm posting the link):

Image

As you can see, the group "f" has been correctly created, but "Francia" should be under "f" instead of "m". Also, "f" should be before "g": sometimes groups are sorted correctly (for example "Austria" is not the first one in the xml file, but it's showed at the top of the list, where it should be!) and sometimes not ("Italia" is one of the first countries listed in the file, but in the list it's after the "u"!) ...

Any ideas?

Thanks anyway.

Upvotes: 0

Views: 785

Answers (2)

Shashi
Shashi

Reputation: 2898

I did like this:

  ZoneDetails zones = new ZoneDetails();
AppUtility.CreateGroupedOC(zones);

 /// <summary>
    /// Groups a passed Contacts ObservableCollection
    /// </summary>
    /// <param name="InitialContactsList">Unordered collection of Contacts</param>
    /// <returns>Grouped Observable Collection of Contacts suitable for the LongListSelector</returns>
    public static ObservableCollection<GroupedOC<ZoneDetail>> CreateGroupedOC(ObservableCollection<ZoneDetail> InitialContactsList)
    {

        //Initialise the Grouped OC to populate and return
        ObservableCollection<GroupedOC<ZoneDetail>> GroupedContacts = new ObservableCollection<GroupedOC<ZoneDetail>>();

        //first sort our contacts collection into a temp List using LINQ
        var SortedList = (from con in InitialContactsList
                          orderby con.Name
                          select con).ToList();

        //Now enumerate throw the alphabet creating empty groups objects
        //This ensure that the whole alphabet exists even if we never populate them
        string Alpha = "#abcdefghijklmnopqrstuvwxyz";
        foreach (char c in Alpha)
        {
            //Create GroupedOC for given letter
            GroupedOC<ZoneDetail> thisGOC = new GroupedOC<ZoneDetail>(c.ToString());

            //Create a temp list with the appropriate Contacts that have this NameKey
            var SubsetOfCons = (from con in SortedList
                                where (string.Compare(con.Key, c.ToString(), StringComparison.OrdinalIgnoreCase) == 0)
                                select con).ToList<ZoneDetail>();

            //Populate the GroupedOC
            foreach (ZoneDetail csm in SubsetOfCons)
            {
                thisGOC.Add(csm);
            }

            //Add this GroupedOC to the observable collection that is being returned
            // and the LongListSelector can be bound to.
            GroupedContacts.Add(thisGOC);
        }
        return GroupedContacts;
    }

public class GroupedOC<T> : ObservableCollection<T>
{
    /// <summary>
    /// The Group Title
    /// </summary>
    public string Title
    {
        get;
        set;
    }

    /// <summary>
    /// Constructor ensure that a Group Title is included
    /// </summary>
    /// <param name="name">string to be used as the Group Title</param>
    public GroupedOC(string name)
    {
        this.Title = name;
    }

    /// <summary>
    /// Returns true if the group has a count more than zero
    /// </summary>
    public bool HasItems
    {
        get {return (Count != 0);}
    }
}

Upvotes: 0

Ilya Builuk
Ilya Builuk

Reputation: 2179

Have you tried to use different grouping approach? The silverlight toolkit contains the good sample which shows how you can implement grouping:

List movies = new List();
//Fill movie collection
 ...

var moviesByCategory = from movie in movies
                       group movie by movie.Category into c
                       orderby c.Key
                       select new PublicGrouping(c);
linqMovies.ItemsSource = moviesByCategory;

Where PublicGrouping is:

 /// 
    /// A class used to expose the Key property on a dynamically-created Linq grouping.
    /// The grouping will be generated as an internal class, so the Key property will not
    /// otherwise be available to databind.
    /// 
    /// The type of the key.
    /// The type of the items.
    public class PublicGrouping : IGrouping
    {
        private readonly IGrouping _internalGrouping;

        public PublicGrouping(IGrouping internalGrouping)
        {
            _internalGrouping = internalGrouping;
        }

        public override bool Equals(object obj)
        {
            PublicGrouping that = obj as PublicGrouping;

            return (that != null) && (this.Key.Equals(that.Key));
        }

        public override int GetHashCode()
        {
            return Key.GetHashCode();
        }

        #region IGrouping Members

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

        #endregion

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return _internalGrouping.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _internalGrouping.GetEnumerator();
        }

        #endregion
    }

Upvotes: 1

Related Questions