A Simple Silverlight CRUD Example
Jun
21
Written by:
6/21/2010 8:16 PM

Silverlight is different because it communicates with the website that launches it using asynchronous communication. Learning how to design applications this way can be a bit challenging.
So I created an example, end-to-end, that achieves these goals:
- Creates, Reads, Updates, and Deletes records from the database
- Implements Forms based security
- Implements "Granular Security" ("only allow User One to see, edit, and create their own Tasks")
- Implements View Model Style
View Model Style
View Model Style allows a programmer to create an application that has absolutely no UI (user interface). The programmer only creates a ViewModel and a Model. A designer with no programming ability at all, is then able to start with a blank page and completely create the View (UI) in Microsoft Expression Blend 4 (or higher). If you are new to View Model Style it is suggested that you read Silverlight View Model Style : An (Overly) Simplified Explanation for an introduction.
Website Application
Make a database table:

Make web service methods:
[WebService(Namespace = "http://OpenLightGroup.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService : System.Web.Services.WebService
{
#region GetCurrentUserID
private int GetCurrentUserID()
{
int intUserID = -1;
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// Get the current user
intUserID = Convert.ToInt32(HttpContext.Current.User.Identity.Name);
}
return intUserID;
}
#endregion
// Web Methods
#region GetTasks
[WebMethod]
public List<Task> GetTasks()
{
// Create a collection to hold the results
List<Task> colResult = new List<Task>();
DataClasses1DataContext DB = new DataClasses1DataContext();
var colTasks = from Tasks in DB.Tasks
where Tasks.UserID == GetCurrentUserID()
select Tasks;
// Loop thru the Tasks
foreach (var item in colTasks)
{
// Create a Task
Task tmpTask = new Task();
// Set only the TaskID and the Name
// We do this because Description could be
// a large amount of data that will slow down
// the application and we don't need it now
tmpTask.TaskID = item.TaskID;
tmpTask.TaskName = item.TaskName;
// Add to the final results
colResult.Add(tmpTask);
}
return colResult;
}
#endregion
#region GetTask
[WebMethod]
public Task GetTask(int TaskID)
{
DataClasses1DataContext DB = new DataClasses1DataContext();
var result = (from Tasks in DB.Tasks
where Tasks.TaskID == TaskID
where Tasks.UserID == GetCurrentUserID()
select Tasks).FirstOrDefault();
return result;
}
#endregion
#region DeleteTask
[WebMethod]
public string DeleteTask(int TaskID)
{
string strError = "";
DataClasses1DataContext DB = new DataClasses1DataContext();
try
{
var result = (from Tasks in DB.Tasks
where Tasks.TaskID == TaskID
where Tasks.UserID == GetCurrentUserID()
select Tasks).FirstOrDefault();
if (result != null)
{
DB.Tasks.DeleteOnSubmit(result);
DB.SubmitChanges();
}
}
catch (Exception ex)
{
strError = ex.Message;
}
return strError;
}
#endregion
#region UpdateTask
[WebMethod]
public string UpdateTask(Task objTask)
{
string strError = "";
DataClasses1DataContext DB = new DataClasses1DataContext();
try
{
var result = (from Tasks in DB.Tasks
where Tasks.TaskID == objTask.TaskID
where Tasks.UserID == GetCurrentUserID()
select Tasks).FirstOrDefault();
if (result != null)
{
result.TaskDescription = objTask.TaskDescription;
result.TaskName = objTask.TaskName;
DB.SubmitChanges();
}
}
catch (Exception ex)
{
strError = ex.Message;
}
return strError;
}
#endregion
#region InsertTask
[WebMethod]
public Task InsertTask(Task objTask)
{
DataClasses1DataContext DB = new DataClasses1DataContext();
try
{
Task InsertTask = new Task();
InsertTask.TaskDescription = objTask.TaskDescription;
InsertTask.TaskName = objTask.TaskName;
InsertTask.UserID = GetCurrentUserID();
DB.Tasks.InsertOnSubmit(InsertTask);
DB.SubmitChanges();
// Set the TaskID
objTask.TaskID = InsertTask.TaskID;
}
catch (Exception ex)
{
// Log the error
objTask.TaskID = -1;
objTask.TaskDescription = ex.Message;
}
return objTask;
}
#endregion
}
Silverlight Application

Download and install RX Extensions from: http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

Add references to:
- System.CoreEx
- System.Observable
- System.Reactive

Add a web reference to the web service.
Insert the following code for the Model:
public class TasksModel
{
#region GetTasks
public static IObservable<IEvent<GetTasksCompletedEventArgs>> GetTasks()
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
IObservable<IEvent<GetTasksCompletedEventArgs>> observable =
Observable.FromEvent<GetTasksCompletedEventArgs>(WS, "GetTasksCompleted");
WS.GetTasksAsync();
return observable;
}
#endregion
#region GetTask
public static IObservable<IEvent<GetTaskCompletedEventArgs>> GetTask(int TaskID)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
IObservable<IEvent<GetTaskCompletedEventArgs>> observable =
Observable.FromEvent<GetTaskCompletedEventArgs>(WS, "GetTaskCompleted");
WS.GetTaskAsync(TaskID);
return observable;
}
#endregion
#region DeleteTask
public static IObservable<IEvent<DeleteTaskCompletedEventArgs>> DeleteTask(int TaskID)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
IObservable<IEvent<DeleteTaskCompletedEventArgs>> observable =
Observable.FromEvent<DeleteTaskCompletedEventArgs>(WS, "DeleteTaskCompleted");
WS.DeleteTaskAsync(TaskID);
return observable;
}
#endregion
#region UpdateTask
public static IObservable<IEvent<UpdateTaskCompletedEventArgs>> UpdateTask(Task objTask)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
IObservable<IEvent<UpdateTaskCompletedEventArgs>> observable =
Observable.FromEvent<UpdateTaskCompletedEventArgs>(WS, "UpdateTaskCompleted");
WS.UpdateTaskAsync(objTask);
return observable;
}
#endregion
#region InsertTask
public static IObservable<IEvent<InsertTaskCompletedEventArgs>> InsertTask(Task objTask)
{
// Set up web service call
WebServiceSoapClient WS = new WebServiceSoapClient();
// Set the EndpointAddress
WS.Endpoint.Address = new EndpointAddress(GetBaseAddress());
IObservable<IEvent<InsertTaskCompletedEventArgs>> observable =
Observable.FromEvent<InsertTaskCompletedEventArgs>(WS, "InsertTaskCompleted");
WS.InsertTaskAsync(objTask);
return observable;
}
#endregion
// Utility
#region GetBaseAddress
private static Uri GetBaseAddress()
{
// Get the web address of the .xap that launched this application
string strBaseWebAddress = App.Current.Host.Source.AbsoluteUri;
// Find the position of the ClientBin directory
int PositionOfClientBin =
App.Current.Host.Source.AbsoluteUri.ToLower().IndexOf(@"/clientbin");
// Strip off everything after the ClientBin directory
strBaseWebAddress = Strings.Left(strBaseWebAddress, PositionOfClientBin);
// Create a URI
Uri UriWebService = new Uri(String.Format(@"{0}/WebService.asmx", strBaseWebAddress));
// Return the base address
return UriWebService;
}
#endregion
}
Use the following code for the View Model:
public class MainPageModel : INotifyPropertyChanged
{
public MainPageModel()
{
// Set the command property
GetTasksCommand = new DelegateCommand(GetTasks, CanGetTasks);
GetTaskCommand = new DelegateCommand(GetTask, CanGetTask);
DeleteTaskCommand = new DelegateCommand(DeleteTask, CanDeleteTask);
UpdateTaskCommand = new DelegateCommand(UpdateTask, CanUpdateTask);
AddNewTaskCommand = new DelegateCommand(AddNewTask, CanAddNewTask);
// The following line prevents Expression Blend
// from showing an error when in design mode
if (!DesignerProperties.IsInDesignTool)
{
// Get the Tasks for the current user
GetTasks();
// Set Visibility
HasCurrentTask = Visibility.Collapsed;
AddVisibility = Visibility.Visible;
UpdateVisibility = Visibility.Collapsed;
DeleteVisibility = Visibility.Collapsed;
}
}
// Commands
#region GetTasksCommand
public ICommand GetTasksCommand { get; set; }
public void GetTasks(object param)
{
GetTasks();
}
private bool CanGetTasks(object param)
{
return true;
}
#endregion
#region GetTaskCommand
public ICommand GetTaskCommand { get; set; }
public void GetTask(object param)
{
// Get the Task that was passed as a parameter
Task objTask = (Task)param;
// Call GetTask to get and set
// the CurrentTask property
GetTask(objTask.TaskID);
}
private bool CanGetTask(object param)
{
// Only allow this ICommand to fire
// if a Task was passed as a parameter
return ((param as Task) != null);
}
#endregion
#region DeleteTaskCommand
public ICommand DeleteTaskCommand { get; set; }
public void DeleteTask(object param)
{
if (CurrentTask.TaskID == -1)
{
// This is a new Task
SetToNewTask();
}
else
{
// This is an Existing Task
DeleteTask(CurrentTask);
}
}
private bool CanDeleteTask(object param)
{
// Do not allow if there is no Current Task
return (CurrentTask != null);
}
#endregion
#region UpdateTaskCommand
public ICommand UpdateTaskCommand { get; set; }
public void UpdateTask(object param)
{
if (CurrentTask.TaskID == -1)
{
// This is a new Task
InsertTask(CurrentTask);
}
else
{
// This is an Update
UpdateTask(CurrentTask);
}
}
private bool CanUpdateTask(object param)
{
// Do not allow if there is no Current Task
return (CurrentTask != null);
}
#endregion
#region AddNewTaskCommand
public ICommand AddNewTaskCommand { get; set; }
public void AddNewTask(object param)
{
SetToNewTask();
}
private bool CanAddNewTask(object param)
{
return true;
}
#endregion
// Operations
#region GetTasks
private void GetTasks()
{
// Clear the current Tasks
colTasks.Clear();
// Call the Model to get the collection of Tasks
TasksModel.GetTasks().Subscribe(p =>
{
if (p.EventArgs.Error == null)
{
// loop thru each item
foreach (var Task in p.EventArgs.Result)
{
// Add to the colTasks collection
colTasks.Add(Task);
}
// Count the records returned
if (colTasks.Count == 0)
{
// If there are no records, indicate that
Message = "No Records Found";
// Set HasCurrentTask
HasCurrentTask = Visibility.Collapsed;
// We have no Tasks so set HasTasks
HasTasks = Visibility.Collapsed;
}
else
{
// We have Tasks so set HasTasks
HasTasks = Visibility.Visible;
}
}
});
}
#endregion
#region GetTask
private void GetTask(int intTaskID)
{
// Call the Model to get the Task
TasksModel.GetTask(intTaskID).Subscribe(p =>
{
if (p.EventArgs.Error == null)
{
// Set the CurrentTask Property
CurrentTask = p.EventArgs.Result;
// Set Visibility
HasCurrentTask = Visibility.Visible;
AddVisibility = Visibility.Visible;
UpdateVisibility = Visibility.Visible;
DeleteVisibility = Visibility.Visible;
}
});
}
#endregion
#region DeleteTask
private void DeleteTask(Task objTask)
{
// Call the Model to delete the Task
TasksModel.DeleteTask(objTask.TaskID).Subscribe(p =>
{
if (p.EventArgs.Error == null)
{
// Set the Error Property
Message = p.EventArgs.Result;
// Set current Task to null
CurrentTask = null;
// Update the Tasks list
GetTasks();
// Set Visibility
HasCurrentTask = Visibility.Collapsed;
AddVisibility = Visibility.Visible;
UpdateVisibility = Visibility.Collapsed;
DeleteVisibility = Visibility.Collapsed;
}
});
}
#endregion
#region UpdateTask
private void UpdateTask(Task objTask)
{
// Call the Model to UpdateTask the Task
TasksModel.UpdateTask(objTask).Subscribe(p =>
{
if (p.EventArgs.Error == null)
{
// Set the Error Property
Message = p.EventArgs.Result;
// Update the Tasks list
GetTasks();
// Set Visibility
HasCurrentTask = Visibility.Visible;
AddVisibility = Visibility.Visible;
UpdateVisibility = Visibility.Visible;
DeleteVisibility = Visibility.Visible;
}
});
}
#endregion
#region InsertTask
private void InsertTask(Task objTask)
{
// Call the Model to Insert the Task
TasksModel.InsertTask(objTask).Subscribe(p =>
{
if (p.EventArgs.Error == null)
{
// Set the CurrentTask Property
CurrentTask = p.EventArgs.Result;
// Update the Tasks list
GetTasks();
// Set Visibility
HasCurrentTask = Visibility.Visible;
AddVisibility = Visibility.Visible;
UpdateVisibility = Visibility.Visible;
DeleteVisibility = Visibility.Visible;
}
});
}
#endregion
#region SetToNewTask
private void SetToNewTask()
{
// Create a empty Task
// so form will be blank
Task objTask = new Task();
// Set TaskID = -1 so we know it's
// a new Task
objTask.TaskID = -1;
// Set the CurrentTask Property
CurrentTask = objTask;
// Set Visibility
HasCurrentTask = Visibility.Visible;
AddVisibility = Visibility.Collapsed;
UpdateVisibility = Visibility.Visible;
DeleteVisibility = Visibility.Collapsed;
}
#endregion
// Properties
#region CurrentTask
private Task _CurrentTask = new Task();
public Task CurrentTask
{
get { return _CurrentTask; }
private set
{
if (CurrentTask == value)
{
return;
}
_CurrentTask = value;
this.NotifyPropertyChanged("CurrentTask");
}
}
#endregion
#region AddVisibility
private Visibility _AddVisibility = Visibility.Visible;
public Visibility AddVisibility
{
get { return _AddVisibility; }
private set
{
if (AddVisibility == value)
{
return;
}
_AddVisibility = value;
this.NotifyPropertyChanged("AddVisibility");
}
}
#endregion
#region UpdateVisibility
private Visibility _UpdateVisibility = Visibility.Visible;
public Visibility UpdateVisibility
{
get { return _UpdateVisibility; }
private set
{
if (UpdateVisibility == value)
{
return;
}
_UpdateVisibility = value;
this.NotifyPropertyChanged("UpdateVisibility");
}
}
#endregion
#region DeleteVisibility
private Visibility _DeleteVisibility = Visibility.Visible;
public Visibility DeleteVisibility
{
get { return _DeleteVisibility; }
private set
{
if (DeleteVisibility == value)
{
return;
}
_DeleteVisibility = value;
this.NotifyPropertyChanged("DeleteVisibility");
}
}
#endregion
#region HasTasks
private Visibility _HasTasks = Visibility.Collapsed;
public Visibility HasTasks
{
get { return _HasTasks; }
private set
{
if (HasTasks == value)
{
return;
}
_HasTasks = value;
this.NotifyPropertyChanged("HasTasks");
}
}
#endregion
#region HasCurrentTask
private Visibility _HasCurrentTask = Visibility.Collapsed;
public Visibility HasCurrentTask
{
get { return _HasCurrentTask; }
private set
{
if (HasCurrentTask == value)
{
return;
}
_HasCurrentTask = value;
this.NotifyPropertyChanged("HasCurrentTask");
}
}
#endregion
#region Message
private string _Message;
public string Message
{
get { return _Message; }
private set
{
if (Message == value)
{
return;
}
_Message = value;
this.NotifyPropertyChanged("Message");
}
}
#endregion
// Collections
#region colTasks
private ObservableCollection<Task> _colTasks
= new ObservableCollection<Task>();
public ObservableCollection<Task> colTasks
{
get { return _colTasks; }
private set
{
if (colTasks == value)
{
return;
}
_colTasks = value;
this.NotifyPropertyChanged("colTasks");
}
}
#endregion
// Utility
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}

Hook up the View to the View Model.
Live example: http://silverlight.adefwebserver.com/RIATasks/
Download Sample Code: WebApplication1.zip
7 comment(s) so far...
Re: A Simple Silverlight CRUD Example
Great article. Very easy to learn.
By Daniel on
6/22/2010 3:52 AM
|
Re: A Simple Silverlight CRUD Example
@Daniel - Thanks for the feedback. I hope this helps.
By Michael Washington on
6/22/2010 4:07 AM
|
Re: A Simple Silverlight CRUD Example
Very helpful Mr. Washington thank you.
By Mo_Hassan on
6/22/2010 8:07 PM
|
Re: A Simple Silverlight CRUD Example
@Mo_Hassan - I appreciate the feedback, thanks!
By Michael Washington on
6/22/2010 8:07 PM
|
Re: A Simple Silverlight CRUD Example
Thank you for taking the time to explain this.
By Stephen Patten on
6/23/2010 4:46 PM
|
Re: A Simple Silverlight CRUD Example
@ Stephen Patten - Thank you for the feedback. I just hope you are able to easily understand this and simply get moving on your own projects :) I hope you simply say, "Oh that's no big deal".
By Michael Washington on
6/23/2010 4:49 PM
|
Re: A Simple Silverlight CRUD Example
This looks like such a great tutorial that I could learn from but I am a vb programmer and can not translate your code to vb. Is there any way there is a post that shows all this in VB?
By Matt on
6/12/2011 2:24 PM
|