ListBox ContextMenu with MVVM in Windows Phone
published on: 12/1/2011 | Views: N/A | Tags: WP7Toolkit MVVM Binding ListBox
by WindowsPhoneGeek
In this article I am going to talk about using the Windows Phone Toolkit ContextMenu with MVVM. We will implement a ListBox bound to a collection of cities. Each ListBox item will have its own ContextMenu that allows the user to remove an item or see information about the item in a message box.
For reference you can also take a look at our previous article:
- Windows Phone Mango: Getting Started with MVVM in 10 Minutes
- "Silverlight for Windows Phone Toolkit In Depth" free e-book
Before we begin let me first mention that in this example I will use the MVVM Light toolkit installed via NuGet and the Silverlight for Windows Phone toolkit as well.
For more information take a look at: How to install MVVM Light Toolkit via NuGet and How to install Windows Phone Toolkit Aug 2011 via NuGet
To begin with follow the steps:
Step1: Define the Model. We will create a new class called City and will add the following code inside:
public class City
{
public string Name
{
get;
set;
}
public string Country
{
get;
set;
}
public string Language
{
get;
set;
}
}
Step2: The View Model. When you install the MVVM light toolkit via NuGet, it automatically adds to the project a MainViewModel and a ViewModelLocator classes.
Step3: Add a new CityList property inside the MainViewModel class:
private IList<City> cityList = null;
public IEnumerable<City> CityList
{
get
{
if (this.cityList == null)
{
this.cityList = this.GetCityList();
}
return this.cityList;
}
}
Step4: Add a new method called GetCityList() that will be used for initializing the CityList collection inside MainViewModel class :
private IList<City> GetCityList()
{
IList<City> cityList = new ObservableCollection<City>();
cityList.Add(new City() { Name = "Madrid", Country = "ES", Language = "Spanish" });
cityList.Add(new City() { Name = "Barcelona", Country = "ES", Language = "Spanish" });
cityList.Add(new City() { Name = "Mallorca", Country = "ES", Language = "Spanish" });
cityList.Add(new City() { Name = "Las Vegas", Country = "US", Language = "English" });
cityList.Add(new City() { Name = "Dalas", Country = "US", Language = "English" });
cityList.Add(new City() { Name = "New York", Country = "US", Language = "English" });
cityList.Add(new City() { Name = "London", Country = "UK", Language = "English" });
cityList.Add(new City() { Name = "Mexico", Country = "MX", Language = "Spanish" });
cityList.Add(new City() { Name = "Milan", Country = "IT", Language = "Italian" });
cityList.Add(new City() { Name = "Roma", Country = "IT", Language = "Italian" });
cityList.Add(new City() { Name = "Paris", Country = "FR", Language = "French" });
return cityList;
}
NOTE: It is important that the cityList must be an instance of ObservableCollection otherwise changes to the collection will not be automatically reflected to the UI.
Step5: Set the DataContext of the LayoutRoot panel of the page to the MainViewModel:
<Grid x:Name="LayoutRoot" Background="Transparent"
DataContext="{Binding Source={StaticResource Locator}, Path=MainVM}">
NOTE: In the above snippet the DataContext is set to the MainVM property of the default ViewModel Locator(defined as a resource in App.xaml) that comes with the MVVM Light template.
Step6: Create a new ListBox in MainPage.xaml and data bind it to the collection of cities:
<ListBox ItemsSource="{Binding CityList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where: xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
Step7: Implement Remove and Show commands in the MainViewModel class as follows:
private ICommand removeCommand = null;
private ICommand showCommand = null;
public MainViewModel()
{
this.removeCommand = new RelayCommand<City>(this.RemoveAction);
this.showCommand = new RelayCommand<City>(this.ShowAction);
}
public ICommand RemoveCommand
{
get
{
return this.removeCommand;
}
}
public ICommand ShowCommand
{
get
{
return this.showCommand;
}
}
// NOTE: SelectedItem will not work
// so we pass the city as command parameter
private void RemoveAction(City city)
{
if (city != null)
{
this.cityList.Remove(city);
}
}
private void ShowAction(City city)
{
if (city != null)
{
MessageBox.Show(string.Format("City: {0}", city.Name));
}
}
Step8: Add a ContextMenu inside the ItemTemplate of the ListBox and bind it to the commands:
<ListBox ItemsSource="{Binding CityList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Remove"
Command="{Binding MainVM.RemoveCommand, Source={StaticResource Locator}}"
CommandParameter="{Binding}"/>
<toolkit:MenuItem Header="Show" Command="{Binding MainVM.ShowCommand, Source={StaticResource Locator}}"
CommandParameter="{Binding}"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding Name}">
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
NOTE: When binding the commands we use the fact that the ViewModel Locator uses a static instance of the MainViewModel.
NOTE: The CommandParameter for both commands is bound to the corresponding City item displayed using the ListBox ItemTemplate.
NOTE: MainVM is a property of the ViewModelLocator that returns an instance of MainViewModel:
private static MainViewModel _main;
public MainViewModel MainVM
{
get
{
return _main;
}
}
That was all about data binding a ContextMenu using MVVM Light. The source code is available here:
I hope that the article was helpful.
You can also follow us on Twitter @winphonegeek
Comments
Events detach issue
posted by: Claudiu Farcas on 12/4/2011 12:18:57 AM
Attention!
toolkit:ContextMenu component doesn't detach the attached events(commands) and thus resulting in entire page left in memory when you navigate away .. thus.. memory leaks. I have tried almost the same scenario with Telerik RadContextMenu and it does proper releasing.
So.. be careful on what component you choose or do the proper commands detachings.
Getting the context menu from code
posted by: Peter Lindberg on 12/13/2011 12:38:12 PM
For those interested - I wrote a blogpost on how to access the context menu on listboxitems from codebehind
/Peter
New! WindowsPhoneGeek Component Marketplace
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
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
