Complete Generic MVVM in Silverlight Part II

Vuyiswamb
Posted by in Silverlight category on for Intermediate level | Points: 250 | Views : 8231 red flag
Rating: 5 out of 5  
 1 vote(s)

In the first part of this series I outlined the basic information that you will need to know to get started with MVVM. In this part of the serials I will demonstrate to you how to create a Visual studio structure of MVVM without using any toolkit to help you. After the Structure is in place we will create our model.

Introduction

 

In the first part of this series I outlined the basic information that you will need to know to get started with MVVM. In this part of the serials I will demonstrate to you how to create a Visual studio structure of MVVM without using any toolkit to help you. After the Structure is in place we will create our model.  


Objective


The objective of this article of this second part of the series is to give you a brief structure of the MVVM pattern in Visual Studio.


How Should my Solution Look?


 This is always a problem for beginners in this subject.  Your Solution Explorer should look like this 


 


When you create a new Silverlight application in visual studio, You will get a web application created for you in the solution explorer and the Silverlight application above it as depicted. You start start renaming the folders to follow the MVVM pattern naming convensions. So in the Silverlight project you will have a Viewmodel and the View. So you will have to create these folders, you might be lucky to find that the “View” Folder is created for you. In the website you will notice there is a Folder “Model” Well our Model will be there or it can be a webservice sitting somewhere , but for the purpose of this demonstration i will put everything in the same solution. The Reason you have a model in the website is that you cannot create a webservice in a Silverlight project and you cannot access ado.net directly in Silverlight, which brings us to a point why we have the Model folder in other project. This is because the Model is the one that connects to the database and retrieve the data for us and after the data is begin retrieved, the ViewModel will get the data from the Model and the View will get data from the ViewModel. 


I don’t want to say a lot of things about the ViewModel because it I beyond the scope of this article, but in this part of the series I will explain to you and demonstrate on how you can prepare the Model for the ViewModel. 



Model 


 


The model prepares the data for the ViewModel. We normally use a wcf service to create our model. I am going to show you the complete Model that we will use in the coming series of this article. What you will see in the Model is just data retrieval from the database and some classes to Map the data and that will be all. Let us see what we can get inside the model.


What is inside the Model? 


 


These are the files you will normally have inside the model. I am not against old technologies, but I prefer using a wcf service than a soap web service. Let us start from the bottom.  We have ICustomers.cs. In WCF, this will be other Service Contract. This is the interface that defines our operations.

    

[ServiceContract]

public interface ICustomers

{

 

[OperationContract]

ObservableCollection<CustomersModel> GetCustomers();

 

[OperationContract]

Boolean UpdateCustomers(CustomersModel Model);

 

[OperationContract]

Boolean AddCustomers(CustomersModel Model);

 

[OperationContract]

Boolean DeleteCustomers(CustomersModel Model);

 

}


As you can see that, these are the operations that need to be implemented in the class that will implement these operations. This includes our CRUD. 


The following file is the one that maps what comes from the database to the one going to ViewModel, our function GetCustomers will convert the data from a raw data to the Data that can be understood by the ViewModel, but we normally convert the data so that it can be ready for Silverlight also, we don’t want to do another conversion again in the ViewModel. 


using System;

using System.Collections.Generic;

using System.Configuration;

using System.Data;

using System.Data.SqlClient;

using System.Data.SqlTypes;

using System.Globalization;

using System.ComponentModel;

using System.Runtime.Serialization;

 

namespace MVVM_TestService

{

[DataContract]

public class CustomersModel

{

private int _CustomerID;

private string _CustomerName;

private string _CustomerSurname;

private string _CustomerTelephone;

private string _customeraddrees;

[DataMember]

public int CustomerID

{

get

{

return _CustomerID;

}

set

{

_CustomerID = value;

}

}

 

[DataMember]

public string CustomerName

{

get

{

return _CustomerName;

}

set

{

_CustomerName = value;

}

}

 

[DataMember]

public string CustomerSurname

{

get

{

return _CustomerSurname;

}

set

{

_CustomerSurname = value;

}

}

 

[DataMember]

public string CustomerTelephone

{

get

{

return _CustomerTelephone;

}

set

{

_CustomerTelephone = value;

}

}

 

[DataMember]

public string customeraddrees

{

get

{

return _customeraddrees;

}

set

{

_customeraddrees = value;

}

}

}

}



As you can see these are just setters and getters and nothing else. 


The Following file is Customers.svc, this is a wcf file, your service is accessed through this file, without this file there is no service, though it does not contain any code behind, but you can choose to add one, I separated it for easy readability of my project structure. If you open this file you will find the following


 


As you can see there is References to the files WCF need’s to run your service. 


Now we come to our operation class that implements the Interface and it looks like this including all the crud functions.


public class Customers : ICustomers

{

#region Connection objects

String strCon = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString;

 

SqlCommand cmdselect;

SqlConnection con;

SqlDataAdapter da;

 

#endregion

public ObservableCollection<CustomersModel> GetCustomers()

{

con = new SqlConnection(strCon);

cmdselect = new SqlCommand();

cmdselect.CommandText = "spx_GetCustomers";

cmdselect.CommandType = CommandType.StoredProcedure;

cmdselect.Connection = con;

da = new SqlDataAdapter();

DataTable dtpermissions = new DataTable();

da.SelectCommand = cmdselect;

ObservableCollection<CustomersModel> lstCustomers = new ObservableCollection<CustomersModel>();

 

try

{

con.Open();

da.Fill(dtpermissions);

if (dtpermissions.Rows.Count > 0)

{

for (int i = 0; i < dtpermissions.Rows.Count; i++)

{

CustomersModel m = new CustomersModel();

m.CustomerID = Convert.ToInt32(dtpermissions.Rows[i][0]);

m.CustomerName = dtpermissions.Rows[i][1].ToString();

m.CustomerSurname = dtpermissions.Rows[i][2].ToString();

m.CustomerTelephone = dtpermissions.Rows[i][3].ToString();

m.customeraddrees = dtpermissions.Rows[i][4].ToString();

lstCustomers.Add(m);

}

}

catch (SqlException ex)

{

throw ex;

}

finally

{

con.Close();

}

return lstCustomers;

}

 

//Upadte

 

public Boolean UpdateCustomers(CustomersModel Model)

{

con = new SqlConnection(strCon);

cmdselect = new SqlCommand();

cmdselect.CommandText = "spx_UpdateCustomer";

cmdselect.CommandType = CommandType.StoredProcedure;

cmdselect.Connection = con;

cmdselect.Parameters.Add("@CUSTOMERNAME", SqlDbType.VarChar).Value = Model.CustomerName;

cmdselect.Parameters.Add("@CUSTOMERSURNAME", SqlDbType.VarChar).Value = Model.CustomerSurname;

cmdselect.Parameters.Add("@CUSTOMERTELEPHONE", SqlDbType.VarChar).Value = Model.CustomerTelephone;

cmdselect.Parameters.Add("@CUSTOMERADDRESS", SqlDbType.VarChar).Value = Model.customeraddrees;

cmdselect.Parameters.Add("@CUSTOMERID", SqlDbType.Int).Value = Model.CustomerID;

 

Boolean Res = false;

 

try

{

con.Open();

cmdselect.ExecuteNonQuery();

}

catch (SqlException ex)

{

Res = true;

throw ex;

}

finally

{

con.Close();

}

return Res;

}

/// <summary>

///

/// </summary>

/// <param name="Model"></param>

/// <returns></returns>

 

public Boolean AddCustomers(CustomersModel Model)

{

con = new SqlConnection(strCon);

cmdselect = new SqlCommand();

cmdselect.CommandText = "spx_AddCustomer";

cmdselect.CommandType = CommandType.StoredProcedure;

cmdselect.Connection = con;

cmdselect.Parameters.Add("@CUSTOMERNAME", SqlDbType.VarChar).Value = Model.CustomerName;

cmdselect.Parameters.Add("@CUSTOMERSURNAME", SqlDbType.VarChar).Value = Model.CustomerSurname;

cmdselect.Parameters.Add("@CUSTOMERTELEPHONE", SqlDbType.VarChar).Value = Model.CustomerTelephone;

cmdselect.Parameters.Add("@CUSTOMERADDRESS", SqlDbType.VarChar).Value = Model.customeraddrees;

Boolean Res = false;

 

try

{

con.Open();

cmdselect.ExecuteNonQuery();

}

catch (SqlException ex)

{

Res = true;

throw ex;

}

finally

{

con.Close();

}

return Res;

}

//Upadte

 

public Boolean DeleteCustomers(CustomersModel Model)

{

con = new SqlConnection(strCon);

cmdselect = new SqlCommand();

cmdselect.CommandText = "spx_DELETECustomer";

cmdselect.CommandType = CommandType.StoredProcedure;

cmdselect.Connection = con;

cmdselect.Parameters.Add("@CUSTOMERID", SqlDbType.Int).Value = Model.CustomerID;

Boolean Res = false;

try

{

con.Open();

cmdselect.ExecuteNonQuery();

}

catch (SqlException ex)

{

Res = true;

throw ex;

}

finally

{

con.Close();

}

return Res;

}

}      

As you can see I am using the StoredProcedure, I have script my database and here is the Script


USE [Customer]

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

SET ANSI_PADDING ON

GO

CREATE TABLE [CUSTOMERS](

[CUSTOMERID] [int] IDENTITY(1,1) NOT NULL,

[CUSTOMERNAME] [varchar](50) NULL,

[CUSTOMERSURNAME] [varchar](50) NULL,

[CUSTOMERTELEPHONE] [varchar](50) NULL,

[CUSTOMERADDRESS] [varchar](max) NULL,

 

PRIMARY KEY CLUSTERED

(

[CUSTOMERID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

SET ANSI_PADDING OFF

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [spx_UpdateCustomer]

(

@CUSTOMERNAME VARCHAR(50),

@CUSTOMERSURNAME VARCHAR(50),

@CUSTOMERTELEPHONE VARCHAR(50),

@CUSTOMERADDRESS VARCHAR(100),

@CUSTOMERID INT

)

AS

UPDATE CUSTOMERS

SET CUSTOMERNAME = @CUSTOMERNAME,

CUSTOMERSURNAME =@CUSTOMERSURNAME,

CUSTOMERTELEPHONE = @CUSTOMERTELEPHONE,

CUSTOMERADDRESS = @CUSTOMERADDRESS

WHERE CUSTOMERID = @CUSTOMERID

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [spx_GetCustomers]

AS

SELECT * FROM CUSTOMERS

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [spx_DELETECustomer]

(

@CUSTOMERID INT

)

AS

DELETE CUSTOMERS

WHERE CUSTOMERID = @CUSTOMERID

GO

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROC [spx_AddCustomer]

(

@CUSTOMERNAME VARCHAR(50),

@CUSTOMERSURNAME VARCHAR(50),

@CUSTOMERTELEPHONE VARCHAR(50),

@CUSTOMERADDRESS VARCHAR(100)

)

AS

INSERT INTO CUSTOMERS

VALUES(@CUSTOMERNAME,@CUSTOMERSURNAME,@CUSTOMERTELEPHONE,@CUSTOMERADDRESS)

GO


I have explained to you about all the files needed in the model. There are other two extra files, the Policy files. You will only need them when you debug your application so that you will not run into cross domain exceptions, but after you are done, you can just add them to the root directory of the virtual directory in your IIS. I will not go through them; they will be part of the example project that will be in the last part of this series. 



Let us remind our Selves with Part 1


If you remember in the part 1, I explained the purpose of each part of MVVM. 



 



The Model prepares the Data for the ViewModel and all the inserts, Update’s, Delete’s are done through the Model. The ViewModel can’t Update or do anything on the Data without the Model. 


Conclusion


This part of the series looked at the Model; in the Next part of this series we are going to consume the model from the ViewModel. 


Thank you for Visiting Dotnetfunda

Page copy protected against web site content infringement by Copyscape

About the Author

Vuyiswamb
Full Name: Vuyiswa Maseko
Member Level: NotApplicable
Member Status: Member,MVP,Administrator
Member Since: 7/6/2008 11:50:44 PM
Country: South Africa
Thank you for posting at Dotnetfunda [Administrator]
http://www.Dotnetfunda.com
Vuyiswa Junius Maseko is a Founder of Vimalsoft (Pty) Ltd (http://www.vimalsoft.com/) and a forum moderator at www.DotnetFunda. Vuyiswa has been developing for 16 years now. his major strength are C# 1.1,2.0,3.0,3.5,4.0,4.5 and vb.net and sql and his interest were in asp.net, c#, Silverlight,wpf,wcf, wwf and now his interests are in Kinect for Windows,Unity 3D. He has been using .net since the beta version of it. Vuyiswa believes that Kinect and Hololen is the next generation of computing.Thanks to people like Chris Maunder (codeproject), Colin Angus Mackay (codeproject), Dave Kreskowiak (Codeproject), Sheo Narayan (.Netfunda),Rajesh Kumar(Microsoft) They have made vuyiswa what he is today.

Login to vote for this post.

Comments or Responses

Posted by: debal_saha-9451 on: 11/23/2011 | Points: 25
The Article is going interesting .
One thing I want to learn from you "What are inside Clientaccesspolicy.xml" and "Crossdomain.xml" you did not show.
Can you pl publish Source Code ?
Yeah, I'm waiting for next article .Thanks for this nice article
Posted by: Vuyiswamb on: 11/23/2011 | Points: 25
Good Day

The ClientPolicy and Crossdomain will be attached in the part 4 of the Series. Part 3 is comming in 3 Days time

Thank you.

Login to post response

Comment using Facebook(Author doesn't get notification)