Dynamically updating a data bound LongListSelector in Windows Phone
published on: 6/28/2011 | Views: N/A | Tags: WP7Toolkit Binding LongListSelector
by WindowsPhoneGeek
In this article I am going to talk about how to dynamically update with data the LongListSelector from the Windows Phone 7 Toolkit. As you probably already know LongListSelector is a complex control so I will give a detailed guidelines of how to dynamically add and delete groups and items without rebinding the control.
Getting Started
To begin with, we will have to add a reference to the Microsoft.Phone.Controls.Toolkit.dll assembly which is installed with the toolkit and you can find it in :
C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Toolkit\Nov10\Bin\Microsoft.Phone.Controls.Toolkit.dll.
If you do not want to install the toolkit you can just download the assemblies and add Microsoft.Phone.Controls.Toolkit.dll in your project and reference it from there:
Before you begin make sure that you know the basic concepts of the LongListSelector. For reference you can take a look at our previous posts:
- WP7 LongListSelector in depth | Part1: Visual structure and API
- WP7 LongListSelector in depth | Part2: Data binding scenarios
- Animating the WP7 LongListSelector group items using transitions
Defining the Group<T> class
The Group<T> will inherit from ObservableCollection<T> so that the LongListSelector is notified when the list of cities in a group changes:
public class Group<T> : ObservableCollection<T>
{
public Group(string name, IEnumerable<T> items)
{
this.Key = name;
foreach (T item in items)
{
this.Add(item);
}
}
public override bool Equals(object obj)
{
Group<T> that = obj as Group<T>;
return (that != null) && (this.Key.Equals(that.Key));
}
public string Key
{
get;
set;
}
}
The EnumerableExtensions helper class
This class contains a convenience extension method that creates a new ObservableCollection<T> given an IEnumerable<T>:
public static class EnumerableExtensions
{
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> collection)
{
ObservableCollection<T> observableCollection = new ObservableCollection<T>();
foreach (T item in collection)
{
observableCollection.Add(item);
}
return observableCollection;
}
}
Defining the data source
The first thing we need to do is to define our model. We will use the following simple class (presenting the Country/Language/City relation):
public class City
{
public string Name {get; set;}
public string Country{get; set;}
public string Language{ get; set;}
}
Next we will use a more complex way to define our data source (different than this explained in our "in depth" series of posts):
List<City> source = new List<City>();
source.Add(new City() { Name = "Madrid", Country = "ES", Language = "Spanish" });
source.Add(new City() { Name = "Barcelona", Country = "ES", Language = "Spanish" });
source.Add(new City() { Name = "Mallorca", Country = "ES", Language = "Spanish" });
source.Add(new City() { Name = "Las Vegas", Country = "US", Language = "English" });
City item = new City() { Name = "Dallas", Country = "US", Language = "English" };
source.Add(item);
source.Add(new City() { Name = "New York", Country = "US", Language = "English" });
source.Add(new City() { Name = "London", Country = "UK", Language = "English" });
source.Add(new City() { Name = "Mexico", Country = "MX", Language = "Spanish" });
source.Add(new City() { Name = "Milan", Country = "IT", Language = "Italian" });
source.Add(new City() { Name = "Roma", Country = "IT", Language = "Italian" });
source.Add(new City() { Name = "Paris", Country = "FR", Language = "French" });
Polulating LongListSelector with data
At first we add the following DataTemplates in the page resources:
<phone:PhoneApplicationPage.Resources>
<!-- The template for the list header. This will scroll as a part of the list. -->
<DataTemplate x:Key="citiesListHeader">
<Border Background="Purple">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Cities Header" />
<TextBlock Text ="{Binding Path=ItemsSource.Count, ElementName=citiesListGropus}"/>
</StackPanel>
</Border>
</DataTemplate>
<DataTemplate x:Key="citiesListFooter">
<Border Background="Green">
<TextBlock Text="Cities Footer" />
</Border>
</DataTemplate>
<!-- The template for city items -->
<DataTemplate x:Key="citiesItemTemplate">
<StackPanel Grid.Column="1" VerticalAlignment="Top">
<TextBlock Text="{Binding Name}" FontSize="26" Margin="12,-12,12,6"/>
<TextBlock Text="{Binding Country}" Foreground="GreenYellow"/>
<TextBlock Text="{Binding Language}" Foreground="Orange" />
</StackPanel>
</DataTemplate>
<!-- The group header template, for groups in the main list -->
<DataTemplate x:Key="groupHeaderTemplate">
<Border Background="YellowGreen" Margin="6">
<TextBlock Text="{Binding Key}" FontSize="40" Foreground="Black"/>
</Border>
</DataTemplate>
<DataTemplate x:Key="groupItemTemplate" >
<Border Background="YellowGreen" Width="99" Height="99" Margin="6">
<TextBlock Text="{Binding Key}" FontSize="40" Foreground="Black"/>
</Border>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
Next we will create a new LongListSelector in XAML and will set its ListHeaderTemplate, ListFooterTemplate, GroupHeaderTemplate, GroupItemTemplate as well as the GroupItemsPanel property in this way:
<StackPanel Orientation="Vertical">
<Button x:Name="btnAddGroup" Content="Add Group" Click="btnAddGroup_Click" />
<Button x:Name="btnAddCity" Content="Add City" Click="btnAddCity_Click" />
<Button x:Name="btnDeleteGroup" Content="Delete First Group" Click="btnDeleteGroup_Click" />
</StackPanel>
<toolkit:LongListSelector x:Name="citiesListGropus" Background="Transparent" Grid.Row="1"
ItemTemplate="{StaticResource citiesItemTemplate}"
ListHeaderTemplate="{StaticResource citiesListHeader}"
ListFooterTemplate="{StaticResource citiesListFooter}"
GroupHeaderTemplate="{StaticResource groupHeaderTemplate}"
GroupItemTemplate="{StaticResource groupItemTemplate}" >
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
</toolkit:LongListSelector>
Here is how we will set the ItemsSource of the LongListSelector control:
var cityByCountry = from city in source
group city by city.Country into c
orderby c.Key
select new Group<City>(c.Key, c);
this.cityByCountryList = cityByCountry.ToObservableCollection();
this.citiesListGropus.ItemsSource = this.cityByCountryList;
Note that while the cityByCountryList is of type IList<Group<City>> the actual type of the collection that this variable points to is
ObservableCollection<Group<City>>. This is necessary so that the LongListSelector control is notified when the list of groups changes.
Dynamically Add new Groups in LongListSelector
Here is how you can dynamically add a new group to the LongListSelector:
private void btnAddGroup_Click(object sender, RoutedEventArgs e)
{
string deKey = "DE";
List<City> deCities = new List<City>();
deCities.Add(new City() { Country = deKey, Language = "German", Name = "Berlin" });
deCities.Add(new City() { Country = deKey, Language = "German", Name = "Munich" });
Group<City> deGroup = new Group<City>(deKey, deCities);
this.cityByCountryList.Add(deGroup);
}
Dynamically Add new Items in LongListSelector
Here is how you can dynamically add an item to a group in the LongListSelector:
private void btnAddCity_Click(object sender, RoutedEventArgs e)
{
Group<City> firstGroup = this.cityByCountryList[0];
City newCity = new City() { Country = firstGroup.Key, Language = "Spanish", Name = "Valencia" };
firstGroup.Add(newCity);
}
Dynamically Delete Items in LongListSelector
Here is how you can dynamically delete a group from the LongListSelector:
private void btnDeleteGroup_Click(object sender, RoutedEventArgs e)
{
this.cityByCountryList.RemoveAt(0);
}
You can see the results demonstrated in the following demo video:
That was all about dynamically updating LongListSelector with data. Here is the full source code:
I hope that the post was helpful.
You can also follow us on Twitter @winphonegeek
Comments
This doesnot work for me
posted by: Pratik Agarwal on 7/14/2011 1:05:43 AM
I have not used linq but followed a link on your earlier post and created a group data structure, the data binding works fine for me but the delete just doesn't want to work,
the Group
I am using the 3 seperate LongLists inside a pivotItems, but that shouldnt effect it.
ag.pratik@gmail.com
-pratik
//SearchedResultListLL.ItemsSource = SearchedLGD;
//PublicResultListLL.ItemsSource = PublicLGD;
//MyResultListLL.ItemsSource = MyLGD;
if (menuItem.Header.ToString().Equals("Remove"))
{
MessageBox.Show("Removed temporarily, go to enable disable to remove permanently");
if (SearchedLGD.Contains(DL))
{
int index = SearchedLGD.IndexOf(DL);
SearchedLGD.RemoveAt(index);
}
else if (MyLGD.Contains(DL))
{
int index = MyLGD.IndexOf(DL);
MyLGD.RemoveAt(index);
}
else if (PublicLGD.Contains(DL))
{
int index = PublicLGD.IndexOf(DL);
PublicLGD.RemoveAt(index);
}
}
No Bindable
posted by: Max Pavlov on 8/24/2011 10:42:40 PM
Well, this way you can't dynamically update the long list selector. You can manually add groups (with the ability to add duplicate entries) and no way to just add an item, and have some class define, which group it goes to based on a value of some property. In real word, this demo is useless. I am sorry, but this is honest.
Mostly not bindable
posted by: Max Pavlov on 8/24/2011 11:00:41 PM
Just to explain in datail what I meant:
In the current project, there is no object in memory that I can add a LongListSelector Item to, and the changes would reflect automatically.
We are only able to:
Add an item to the group by Index (try adding a city to FR group for example) We are only able to add a new group at the end of a list, with the ability to have duplicate key groups.
There has to be one bindable collection, and an automatic group sorting for the newly added items. Than, and only than this example would be complete.
Please consider rewriting it in such a way. Thanks.
RE:No Bindable
posted by: winphonegeek on 8/25/2011 12:21:42 AM
The implementation that we described in this article aims to demonstrate that it is possible to "dynamically" add new items. The purpose is not to build a solution that "automatically" reflects changes to the source collection in the control after applying grouping. However, the scenario that you mention is interesting and we will consider adding such article soon.
Rebinding the control.
posted by: Santo on 8/30/2011 12:38:25 PM
Is it posible to rebind data and restore de previous scroll position?
If i bind data, scroll down and then rebind data, the scroll of the longlistSelector changes the position to top.
XML Databiding
posted by: Jonathan on 11/7/2011 11:48:25 AM
Hey guys. Thanks for the great resources on WP7.
My question is this, how would this example be changed if the data is pulled via XML/LINQ?
Cheers
RE: XML Databiding
posted by: winphonegeek on 11/8/2011 12:36:49 PM
In the code samples above, for simplicity, items are added / deleted from specific locations. For example, in the btnAddCity_Click the new City object is always added to the first group.
In your code you will have to be able to determine in which group collection new items have to be added. However, the basic approach stays the same - you need to use observable collections both for groups and items so that the long list selector control is notified when there is a change in the collections.
usage of observableCollection in longlistselector
posted by: ellic on 12/12/2011 11:20:00 AM
Hi,winphonegeek
could you help me figure out this problem, It puzzled me all day long.
coming the link: http://stackoverflow.com/questions/8462359/usage-of-observablecollection-in-longlistselector
Dynamically delete new Item in LongListSelector
posted by: Max on 12/12/2011 2:07:33 PM
With the code helps, I can delete items dynamically, but when I use the code:
Group
//this._wordItems[groupIndex].RemoveAt(inGroupIndex);
certainGroup.RemoveAt(inGroupIndex);
the _wordItems had been updated, the longlistselector had also updated the UI, but the longlistselector just deleted the wrong item. for example, when I decided to delete the _wordItems[1]2, it just deleted the _wordItems[1][1]. And I used the "Debug.WriteLine" to find out that the _wordItems had deleted the _wordItems[1][2] in the right way.It's so strange. Help!
Thx in advence.
Our Top Articles & Free books
- Our FREE e-book: "Windows Phone Toolkit In Depth" 2nd edition
- 400+ Windows Phone Development articles in our Article Index
- 21 WP7 Toolkit in Depth articles covering all controls
- 12 WP7 Coding4Fun Toolkit in Depth articles covering all controls
- Performance Tips when creating WP7 apps
- Creating a WP7 Custom Control in 7 Steps
- WP7 working with VisualStates: How to make a ToggleSwitch from CheckBox
- What makes a WP7 App successful
- Creating theme friendly UI in WP7 using OpacityMask
- Implementing Windows Phone 7 DataTemplateSelector and CustomDataTemplateSelector
- All about Splash Screens in WP7 – Creating animated Splash Screen
- Getting Started with Unit Testing in Silverlight for WP7
- WP7 WatermarkedTextBox custom control
Our Top Tips & Samples
- All about WP7 Isolated Storage series
- WP7 Dynamically Generating DataTemplate in code
- 5 tips for a successful WP7 Marketplace submission
- WP7: Navigating to a page in different assembly
- WP7 ContextMenu: answers to popular questions
- WP7 ListBox: answers to popular questions
- WP7 working with Images: Content vs Resource build action
- WP7 Element Binding samples
- WP7 working with XML: reading, filtering and databinding
- Drawing in WP7: #2 Drawing shapes with finger
- WP7 TextBox Light theme problems - the solution
- Changing the WP7 Panorama Background Image dynamically with Animation

