Saving Silverlight Application's User Settings in DB

This blog helps you save a user's settings in the Database for a #Silverlight Application.

This article is a continuation of my previous article on saving the user settings with Telerik's PersistenceManager.

In the last article we saw how to save the user settings on the local computer, using Isolated Storage. If you want to do that then please just follow This Blog Entry.

If you need the user settings to be stored in the database, so the user will see them irrespective of the machines he uses then this article is for you.

At a high level, the following are the steps you need to use:
  1. Decide a section of the XAML that you want to save for the current user
  2. Create a stream for the UI element using the Telerik PersistenceManager & save them in the database
  3. Load the settings when the user logs in & navigates to the page for which the settings are saved.

To demonstrate this, we will first create a small database with one table.
 


DB Schema.PNG

Note:

I am using varbinary to save the byte stream. A very good reason for why can be found on This Blog Post.

Also the UserId & Key columns together form the primary key in this case, this is to ensure that one user can only save 1 setting per screen section.

You can change this logic as needed.

Then create a WCF RIA Silverlight application that uses this database as its model.

On the client side you will have to add a reference to the following assemblies:
 
Telerik.Windows.Controls
Telerik.Windows.Controls.Input
Telerik.Windows.PersistenceFramework

Once complete, copy the following XAML to the MainPage.xaml:
<Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="35"/> <RowDefinition Height="35*"/> <RowDefinition Height="35"/> </Grid.RowDefinitions> <telerik:RadComboBox Grid.Row="0" Width="200" Margin="0,5,0,0" 
x:Name="myComboBox" SelectionChanged="myComboBox_SelectionChanged"> <telerik:RadComboBoxItem Content="User1"/> <telerik:RadComboBoxItem Content="User2"/> </telerik:RadComboBox> <StackPanel Orientation="Vertical"  
Grid.Row="1" Margin="0,5,0,0" x:Name="myStackPanel"> <telerik:RadNumericUpDown Width="200"/> <CheckBox Width="200" Content="Check Me" Margin="0,5,0,0"/> <RadioButton Content="Check Me" Width="200" Margin="0,5,0,0"/> 
</StackPanel> <telerik:RadButton Content="Save Settings" Click="RadButton_Click" Grid.Row="2" Width="200" HorizontalAlignment="Left"/> <telerik:RadButton Content="Restore Settings" Click="RadButton_Click_1" Grid.Row="2" Width="200" 
HorizontalAlignment="Right"/> </Grid>
Notice, how I have set an ID for the stackpanel. Its because I want to save the contents of this stack panel for the users of my system.

Note: You can use individual controls instead of a container control (e.g. A CheckBox or a Radio Button ) too.

In the code behind, create the following variables on the class level:
private Stream stream;
private Stream loadedStream;
private UserSettingDomainContext _context = new UserSettingDomainContext();

You might need to add appropriate using statements, the following are the ones I have in my project:

using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Telerik.Windows.Persistence;
using userSettingsDemoV2.Web;

Now, on the click of the Save button all we must do is to use the PersistenceManager class & create a stream for our stackPanel control and save it in the database.

 private void RadButton_Click(object sender, RoutedEventArgs e)
{
if (myComboBox.SelectedItem!=null)
{
//Create a Strem using Telerik's PersistenceManager                 PersistenceManager manager = new PersistenceManager();
stream = manager.Save(myStackPanel);
UserSettingTable ust = new UserSettingTable();
if (this.myComboBox.SelectedIndex == 0)
{
ust.UserId = 1;
}
else
{
ust.UserId = 2;
}
ust.key = "settingsForUserPage";
var byteOfStream = new byte[stream.Length];
stream.Read(byteOfStream, 0, (int)stream.Length);
ust.value = byteOfStream;
stream.Close();
_context.UserSettingTables.Add(ust);
_context.SubmitChanges();
}
}

Notice the Key property: ust.key = "settingsForUserPage";

This is any arbitrary string value to uniquely identify the section of the UI that I want to save the settings for.

The following is the code for the Restore Settings button click:

 //Restore settings for stack panel on per user basis  private void RadButton_Click_1(object sender, RoutedEventArgs e)
{
if (loadedStream!=null)
{
//load                 PersistenceManager manager = new PersistenceManager();
loadedStream.Position = 0L;
manager.Load(myStackPanel, loadedStream);    
}
}

Just for the purpose of demonstrations I also have a combo box, with 2 users in it, to mock the Logged In user's identity.

Here is the code on Combo Box's selection change to look into the available values from the database & load the appropriate one.

 //required to understand settings to be loaded for which user, on the UI.   private void myComboBox_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
int userId; 
if (this.myComboBox.SelectedIndex == 0)
{
userId = 1;
}
else
{
userId = 2;
}
var byteOfStream = _context.UserSettingTables.Where(x => x.UserId == userId).FirstOrDefault().value;
loadedStream = new MemoryStream(byteOfStream); 
}

That's all. just fire up the code, select user 1 & click on the save then select user 2 & click on save again. At this time you should see two entries in the database, as in:

Db records.PNG
Click F5 on your browser to imitate a logout & relogin.

Select user 1 & click on Restore Settings, notice that the controls in the stack panel now show the properties you set for User 1.

Change the user selection to User 2 & click on the Restore Settings button again & feel happy for your BIG accomplishment :)

EnJoy Coding!!
 
P.S. See the attached demo project if you want to take it for a ride.