A Simple ToDo List: Persisting Data with the Sterling NoSQL Database
published on: 9/1/2011 | Views: N/A | Tags: LocalDB MVVM Binding
by Mike Gold
Download: ToDo List Source
Introduction
There are some folks out there in the .NET world that have really contributed to some great architectural solutions for the Window's Phone. One is Laurent Bugnion (GalaSoft) who introduced the MVVM-Light framework for the phone. Another is Richard Griffen who leads the WP7 Contrib project. Finally there is a bright guy from Wintellect by the name of Jeremy Likness. He has developed a NoSql database for the Windows Phone that makes persisting data completely mindless. The other nice thing about the Sterling Database is that it is LINQ aware, so you can query its contents using LINQ expressions. In the following article, I will describe for you how you can implement the Sterling database in your phone project with little to no effort and begin persisting your models.
The DB Setup
The Sterling Database is an object persistence mechanism. Once you've set up the sterling database in your application, you can persist your instances at will. First you'll need to add references to the Sterling engine to your project. You can download the sterling engine from codeplex to get you started persisting objects on your phone. The binaries support .NET 4.0, Silverlight 4 and 5 and of course, WP7. Once you've gotten a hold of the assemblies, you can reference them in your phone solution.
Initialization is fairly straightforward and the code is shown in listing 1. First the engine is constructed and activated. Then a database is registered with the engine. The engine will be active until its disposed of at the end of the application.
Listing 1 - Setting up the Sterling Database in app.xaml.cs
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
SetupTheDatabase();
}
private void SetupTheDatabase()
{
// create the sterling engine
_engine = new SterlingEngine();
// create a logger for the sterling db
_logger = new SterlingDefaultLogger(SterlingLogLevel.Verbose);
// activate the sterling engine
_engine.Activate();
// Register your database with the sterling engine and specify its persistence in isolated storage
Database = _engine.SterlingDatabase.RegisterDatabase<ItemsDatabaseInstance>(new IsolatedStorageDriver());
}
Listing 2 shows the ItemsDatabaseInstance we needed to create in order to persist our to do ListItems in the database. The Schema of the database uses the CreaetTableDefinition generic method to specify which classes are registered with the Sterling database. The first generic type parameter in the CreateTableDefinition method is the model type and the second generic type parameter is the key type. The lambda bindings specify the property that we want our class to key off of.
Listing 2 - The Database Definition for Sterling
using System;
using System.Collections.Generic;
using ItemList.Model;
using Wintellect.Sterling.Database;
namespace ItemList
{
public class ItemsDatabaseInstance : BaseDatabaseInstance
{
public override string Name
{
get
{
return "ItemsDatabase";
}
}
protected override List<ITableDefinition> RegisterTables()
{
return new List<ITableDefinition>
{
// we are only registering the To Do list item with the Sterling engine in this example
CreateTableDefinition<ListItem, int>(testModel => testModel.Key)
};
}
protected string DATAINDEX
{
get { return "dataIndex"; }
}
}
}
If we look at the ListItem model we created more closely, we can see that we really don't need to concern ourselves with the Sterling database at all when defining the model. This nice decoupled approach makes using the database to persist our objects very simple. We simply need to provide a Key property and that's it. All the Sterling specific code is located in the Database TableDefinition in Listing 2.
Listing 3 - The Model we are Persisting with the Sterling Database
namespace ItemList.Model
{
public class ModelBase
{
private int _key = -1;
public int Key
{
get { return _key; }
set { _key = value; }
}
}
public class ListItem : ModelBase
{
public bool IsFinished { get; set; }
public string Text { get; set; }
}
}
In order to save the to do ListItems, we created an extension method to ease the task a little. Listing 4 shows how we can encapsulate the access to the App object inside a Save extension method. We can also query the database for the last index and use it to give us the next unique key in the database. (Some people might consider a Guid a better approach here, and you can just as easily do this by making your Key of type Guid). Since there is no danger in this particular app of pulling non-unique keys because the app removes all of the to do items when you click the remove buttons, it should always generate a unique integer for all new items added to the list.
Listing 4 - Extension for Saving our ListItem Model
public static class Extensions
{
public static void Save(this ListItem listItem)
{
int currentIndex = (Application.Current as App).Database.Query<ListItem, int>().Count();
if (listItem.Key == -1)
{
listItem.Key = currentIndex;
}
(Application.Current as App).Database.Save(listItem);
(App.Current as App).Database.Flush();
}
}
Using Sterling in our ViewModel
Using MVVM, we wrap our ListItem in a ListItemViewModel. The ListItemViewModel propagates the models properties to the View. In this example, we chose to persist our model any time we make a change to the properties in our ViewModel. So as soon as any of the setters in our ListItemViewModel are called, we call Save on the property in the model.
Listing 5 - Persisting the Model from the ViewModel when the to do item has changed
using GalaSoft.MvvmLight;
using ItemList.Extensions;
using ItemList.Model;
namespace ItemList.ViewModels
{
public class ListItemViewModel : ViewModelBase
{
public ListItemViewModel()
{
_listItem = new ListItem();
}
private readonly ListItem _listItem;
public ListItemViewModel(ListItem model)
{
_listItem = model;
}
public bool IsFinished
{
get { return _listItem.IsFinished; }
set
{
_listItem.IsFinished = value;
// check state changed, save ListItem model to isolated storage
_listItem.Save();
RaisePropertyChanged("IsFinished");
}
}
public string Text
{
get { return _listItem.Text; }
set
{
_listItem.Text = value;
// text changed, save ListItem model to isolated storage
_listItem.Save();
RaisePropertyChanged("Text");
}
}
}
}
We also want to be able persist the model whenever we add a new ToDo ListItem. We can use a button in our main phone view to bind an ICommand in our main view model and signal that we want to add a new todo list item to our phone screen. The Command Method inside our main view model for adding a new item and saving it is shown in Listing 6.
Listing 6 - Adding a new ToDo list item to our phone view and saving the item to the phone
private void OnAddToDoCommand(string text)
{
var model = new ListItem() {IsFinished = false, Text = text};
model.Save(); // persist it
var listItemViewModel = new ListItemViewModel(model);
ListItems.Add(listItemViewModel);
PromptEntry = false;
}
Conclusion
There is probably a lot more we could have shown you in this example, but this will certainly give you enough to get started with the Sterling engine and persisting simple model objects. I want to give credit to a few others whose ideas helped me get this application working with MVVM. One is Max Paulousky who has a cool bindable application bar button for allowing me to bind menu buttons to my viewmodel. Another shout out goes to Laurent Bugnion (GalaSoft)(Mentioned in the intro) who created the MVVM-Light library which just makes the MVVM pattern more doable task on the phone.
You can also follow us on Twitter @winphonegeek
|
|
About the author:
Mike is a Senior Software Developer in C# and .NET and has been developing Microsoft technology for 22 years. He was a Microsoft MVP for 3 years in Visual C# and has contributed over 200 publications and several books to the .NET community. He currently consults for WellMed in Austin, Texas. Mike is looking forward the possibilities with the Windows Phone. He can be reached at mike@microgold.com |
|
Senior .NET Developer |
|
Comments
Loading Data from the Sterling NoSQL Database
posted by: MikeG on 9/8/2011 6:40:15 AM
After I published this article, I realized I forgot to mention how to load data.
Below is the extension method that is included in the attached source.
public static IEnumerable<ListItem> Load(this IEnumerable<ListItem> listItem)
{
var list = (Application.Current as App).Database.Query<ListItem, int>();
return new ObservableCollection<ListItem>(list.Select(item => item.LazyValue.Value).ToList());
}
Using the Sterling NoSQL Database, you can use a LINQ expression to query the data directly out of the database.
Mr.
posted by: Supreet Tare on 1/22/2012 5:41:51 PM
Hi Mike, Thanks for the article. However there are a couple of things I would like to know about the sample project attached here. 1. You have explained the project on a very high level. Being a novice to sterling I still don't get whats the use of some of the folders/files used in the project. E.g. Bindable Application bar, Repository & ViewModelLocator 2. I am not able to compile the project get following errors
Error 1 'Controls.Shell.BindableApplicationBar' does not implement interface member 'Microsoft.Phone.Shell.IApplicationBar.MiniSize' D:\wp7 Ideas\Demo\ItemList_STERLING Ex\ItemList\BindableApplicationBar\BindableApplicationBar.cs 15 15 ItemList Error 2 'Controls.Shell.BindableApplicationBar' does not implement interface member 'Microsoft.Phone.Shell.IApplicationBar.DefaultSize' D:\wp7 Ideas\Demo\ItemList_STERLING Ex\ItemList\BindableApplicationBar\BindableApplicationBar.cs 15 15 ItemList Error 3 'Controls.Shell.BindableApplicationBar' does not implement interface member 'Microsoft.Phone.Shell.IApplicationBar.Mode' D:\wp7 Ideas\Demo\ItemList_STERLING Ex\ItemList\BindableApplicationBar\BindableApplicationBar.cs 15 15 ItemList
I am looking forward to understand & use Sterling in my wp7 App, & yours is the only simple getting started article available on Sterling that I could understand (in bits & pieces)
hope to hear from you.
Thanks & Regards Supreet Tare
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
