8/10/2019 Mvvm Tutorial
1/17
Windows Phone 8 App using XAML/C#.NET(MVVM)
The purpose of this tutorial is to demonstrate how to apply MVVM (Model-View-ViewModel)
design pattern when developing the windows phone 8 list view app using C#.NET/XAML.
In this scenario we'll leverage Windows Phone 8 SDK for developing Windows Phone 8 ListView App using C#.NET/XAML.
Following xml file is an example xml file which we are going to use as the data source for ourapplication. This file generating from server where our site hosted and can be found using
following url.http://propertymaster.lk/MobileData/prhomedata.xml
http://propertymaster.lk/MobileData/prhomedata.xmlhttp://propertymaster.lk/MobileData/prhomedata.xmlhttp://propertymaster.lk/MobileData/prhomedata.xmlhttp://propertymaster.lk/MobileData/prhomedata.xml8/10/2019 Mvvm Tutorial
2/17
Walkthrough
First off let's create a new project using Visual C# > Windows Phone > Windows Phone Apptemplate
New Project
Select the Target Windows Phone OS Version. In our case it is windows phone 8.
8/10/2019 Mvvm Tutorial
3/17
Then we'll apply MVVM (Model-View-ViewModel) design pattern for development of Real
Estate app.
Solution Explorer
As shown above I created 3 folders for Model, View and ViewModel.
The model encapsulates business logic and data. Please see below how I define PropertyDataclass which has 16 properties:
PropertyData Model Class
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;
namespaceRealEstateApp.Model
8/10/2019 Mvvm Tutorial
4/17
{publicclassPropertyData: INotifyPropertyChanged{
privatestring_propertyCode;privatestring_image1;privatestring_image2;privatestring_image3;privatestring_image4;privatestring_description;privatestring_location;privatestring_type;privatestring_price;privatestring_contactPerson;privatestring_mail;privatestring_mobile;privatestring_landLine;privatestring_latitude;privatestring_longitude;
privatestring_status;
publicstringPropertyCode{
get{
return_propertyCode;}set{
if(value!=_propertyCode){
_propertyCode =value;NotifyPropertyChanged("PropertyCode");
}}
}
publicstringImage1{
get{
return_image1;}set{
if(value!=_image1){
_image1 =value;NotifyPropertyChanged("Image1");
}}
}publicstringImage2{
get{
return_image2;
8/10/2019 Mvvm Tutorial
5/17
}set{
if(value!=_image2){
_image2 =value;NotifyPropertyChanged("Image2");
}}
}
publicstringImage3{
get{
return_image3;}set{
if(value!=_image3)
{ _image3 =value;NotifyPropertyChanged("Image3");
}}
}publicstringImage4{
get{
return_image4;}set{
if(value!=_image4){
_image4 =value;NotifyPropertyChanged("Image4");
}}
}publicstringDescription{
get{
return_description;}set
{if(value!=_description){
_description =value;NotifyPropertyChanged("Description");
}}
}publicstringLocation{
8/10/2019 Mvvm Tutorial
6/17
get{
return_location;}set{
if(value!=_location){
_location =value;NotifyPropertyChanged("Location");
}}
}publicstringType{
get{
return_type;}set
{ if(value!=_type){
_type =value;NotifyPropertyChanged("Type");
}}
}publicstringPrice{
get{
return_price;}
set{
if(value!=_price){
_price =value;NotifyPropertyChanged("Price");
}}
}
publicstringContactPerson{
get{
return_contactPerson;}set{
if(value!=_contactPerson){
_contactPerson =value;NotifyPropertyChanged("ContactPerson");
}}
8/10/2019 Mvvm Tutorial
7/17
}
publicstringMail{
get{
return_mail;}set{
if(value!=_mail){
_mail =value;NotifyPropertyChanged("Mail");
}}
}
publicstringMobile{
get{return_mobile;
}set{
if(value!=_mobile){
_mobile =value;NotifyPropertyChanged("Mobile");
}}
}
publicstringLandLine{
get{
return_landLine;}set{
if(value!=_landLine){
_landLine =value;NotifyPropertyChanged("LandLine");
}}
}
publicstringLatitude{
get{
return_latitude;}set{
8/10/2019 Mvvm Tutorial
8/17
if(value!=_latitude){
_latitude =value;NotifyPropertyChanged("Latitude");
}}
}
publicstringLongitude{
get{
return_longitude;}set{
if(value!=_longitude){
_longitude =value;NotifyPropertyChanged("Longitude");
}}}
publicstringStatus{
get{
return_status;}set{
if(value!=_status){
_status =value;NotifyPropertyChanged("Status");
}}
}
publiceventPropertyChangedEventHandler PropertyChanged;privatevoidNotifyPropertyChanged(StringpropertyName){
PropertyChangedEventHandler handler =PropertyChanged;if(null!=handler){
handler(this, newPropertyChangedEventArgs (propertyName));}
}}
}
8/10/2019 Mvvm Tutorial
9/17
PropertyGroup Model Class
Since we have several property groups (Ex: Houses, Lands, Apartments, Commercial Buildings
etc) I have created another modal class to hold each property within one of property groups.
usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;
namespaceRealEstateApp.Model{
publicclassPropertyGroup: INotifyPropertyChanged{
privateList_properties;privatestring_title;
publicPropertyGroup(){Properties =newList();
}
publicListProperties{
get{
return_properties;}set{
if(value!=_properties)
{_properties =value;NotifyPropertyChanged("Properties");
}}
}
publicstringTitle{
get{
return_title;}set{
if(value!=_title){
_title =value;NotifyPropertyChanged("Title");
}}
}
8/10/2019 Mvvm Tutorial
10/17
The view model encapsulates presentation logic and state. Please see below how I define
ObservableCollection of property group with respective method(s) (LoadData) as a part of theview model.
ViewModel
usingRealEstateApp.Model;usingSystem;usingSystem.Collections.Generic;usingSystem.Collections.ObjectModel;usingSystem.ComponentModel;usingSystem.Linq;usingSystem.Net;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Windows;usingSystem.Xml.Linq;
namespaceRealEstateApp.ViewModel{
publicclassPropertyModel: INotifyPropertyChanged{
publicObservableCollectionHomes { get; privateset; }publicObservableCollectionLands { get; privateset; }
publicboolIsDataLoaded { get; set; }
publicPropertyModel(){
this.Homes =newObservableCollection();this.Lands =newObservableCollection();
}
publicvoidLoadData(){
//Load data into the modelWebClientwchome =newWebClient();wchome.DownloadStringCompleted +=new
DownloadStringCompletedEventHandler (DownloadedHomes);wchome.DownloadStringAsync(new
Uri("http://propertymaster.lk/MobileData/prhomedata.xml" , UriKind.Absolute));
publiceventPropertyChangedEventHandler PropertyChanged;privatevoidNotifyPropertyChanged(StringpropertyName){
PropertyChangedEventHandler handler =PropertyChanged;if(null!=handler){
handler(this, newPropertyChangedEventArgs (propertyName));}
}}
}
8/10/2019 Mvvm Tutorial
11/17
WebClientwclands =newWebClient();wclands.DownloadStringCompleted +=new
DownloadStringCompletedEventHandler (DownloadedLands);wclands.DownloadStringAsync(new
Uri("http://propertymaster.lk/MobileData/prlanddata.xml" , UriKind.Absolute));
this.IsDataLoaded =true;}
publicvoidDownloadedHomes(objectsender, DownloadStringCompletedEventArgs e){
if(e.Result ==null||e.Error !=null){
MessageBox.Show("There was an error downloading the XML-file");}else{
PropertyGrouphomedata =newPropertyGroup();homedata.Title ="Homes";
XDocumentxDoc =XDocument.Parse(e.Result, LoadOptions.None);varquery =fromdesc inxDoc.Descendants("PropertyData")
selectnewPropertyData{
PropertyCode =(string)desc.Attribute("PropertyCode"),Image1 =
(string)"http://propertymaster.lk/UplodedImages/Thumb/" +(string)desc.Attribute("Image1"),
Image2 =(string)"http://propertymaster.lk/UplodedImages/Thumb/" +(string)desc.Attribute("Image2"),
Image3 =(string)"http://propertymaster.lk/UplodedImages/Thumb/" +
(string)desc.Attribute("Image3"),Location =(string)desc.Attribute("Location"),Description =(string)desc.Attribute("Description"),Type =(string)desc.Attribute("Type"),ContactPerson =
(string)desc.Attribute("ContactPerson"),Mail =(string)desc.Attribute("Mail"),Mobile =(string)desc.Attribute("Mobile"),LandLine =(string)desc.Attribute("LandLine"),Price =(string)desc.Attribute("Price"),Latitude =(string)desc.Attribute("Latitude"),Longitude =(string)desc.Attribute("Longitude"),Status =(string)desc.Attribute("Status"),
};
foreach(varitem inquery){
homedata.Properties.Add(item);}Homes.Add(homedata);
}}
publicvoidDownloadedLands(objectsender, DownloadStringCompletedEventArgs e)
8/10/2019 Mvvm Tutorial
12/17
{if(e.Result ==null||e.Error !=null){
MessageBox.Show("There was an error downloading the XML-file");}else{
PropertyGrouplanddata =newPropertyGroup();landdata.Title ="Lands";
XDocumentxDoc =XDocument.Parse(e.Result, LoadOptions.None);varquery =fromdesc inxDoc.Descendants("PropertyData")
selectnewPropertyData{
PropertyCode =(string)desc.Attribute("PropertyCode"),Image1 =
(string)"http://propertymaster.lk/UplodedImages/Thumb/" +(string)desc.Attribute("Image1"),
Image2 =(string)"http://propertymaster.lk/UplodedImages/Thumb/" +
(string)desc.Attribute("Image2"),Image3 =(string)"http://propertymaster.lk/UplodedImages/Thumb/" +(string)desc.Attribute("Image3"),
Location =(string)desc.Attribute("Location"),Description =(string)desc.Attribute("Description"),Type =(string)desc.Attribute("Type"),ContactPerson =
(string)desc.Attribute("ContactPerson"),Mail =(string)desc.Attribute("Mail"),Mobile =(string)desc.Attribute("Mobile"),LandLine =(string)desc.Attribute("LandLine"),Price =(string)desc.Attribute("Price"),Latitude =(string)desc.Attribute("Latitude"),
Longitude =(string)desc.Attribute("Longitude"),Status =(string)desc.Attribute("Status"),
};
foreach(varitem inquery){
landdata.Properties.Add(item);}Lands.Add(landdata);
}}
publiceventPropertyChangedEventHandler PropertyChanged;privatevoidNotifyPropertyChanged(StringpropertyName)
{PropertyChangedEventHandler handler =PropertyChanged;if(null!=handler){
handler(this, newPropertyChangedEventArgs (propertyName));}
}}
}
8/10/2019 Mvvm Tutorial
13/17
Now add following method to your app.xaml.csfile as follows. Please see below how I
instantiate global object of view model class to retrieve a list of property groups.
usingSystem;usingSystem.Diagnostics;usingSystem.Resources;
usingSystem.Windows;usingSystem.Windows.Markup;usingSystem.Windows.Navigation;usingMicrosoft.Phone.Controls;usingMicrosoft.Phone.Shell;usingRealEstateApp.Resources;usingRealEstateApp.ViewModel;
namespaceRealEstateApp{
publicpartialclassApp: Application{
privatestaticPropertyModelviewModel =null;
publicstaticPropertyModelViewModel{
get{
if(viewModel ==null){
viewModel =newPropertyModel();viewModel.LoadData();
}
returnviewModel;}
}
The view encapsulates the UI and any UI logic. Please see below how I use global object of view
model class to retrieve a list of property groups. In any case if our view modal doesnt load thedata, this code segment will ensure loading the data before application page is load.
View (PropertyList.xaml.cs)
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Navigation;usingMicrosoft.Phone.Controls;usingMicrosoft.Phone.Shell;usingRealEstateApp.Resources;usingSystem.Xml.Serialization;usingSystem.Xml.Linq;usingRealEstateApp.ViewModel;
namespaceRealEstateApp.View
8/10/2019 Mvvm Tutorial
14/17
{publicpartialclassPropertyList: PhoneApplicationPage{
publicPropertyList(){
InitializeComponent();
// Set the data context of the listbox control to the sample dataDataContext =App.ViewModel;
}
// Load data for the ViewModel ItemsprotectedoverridevoidOnNavigatedTo(NavigationEventArgse){
if(!App.ViewModel.IsDataLoaded){
App.ViewModel.LoadData();
}}
}}
Then I use bindings to link property data to respective UI elements for display
XAML (PropertyList.xaml)
8/10/2019 Mvvm Tutorial
15/17
Margin="5, 0, 0, 0">
8/10/2019 Mvvm Tutorial
16/17
TextTrimming="WordEllipsis"Style="{StaticResource
PhoneTextTitle2Style}"Foreground="#fff"Grid.Row="0"Grid.Column="1"
Grid.ColumnSpan="2"HorizontalAlignment="Left"
VerticalAlignment="Top"Margin="10,-10,0,0"/>
Please note thatLongListSelectorcontrol was specifically designed for phone scenarios and it isencouraged to use theLongListSelectorinstead ofListBoxfor phone apps.
8/10/2019 Mvvm Tutorial
17/17
PropertyList.xaml (PropertyListTemplate)
As the result, our Real Estate application now will look like below.
Result
Author:
Asela Chamara Fernando(B.Sc. (Hons), M.Sc. (Colombo))
Contact Details:
Phone : +94776073011Email :[email protected],
:[email protected] : aselachamara1
Tags:MVVM, Model-View-ViewModel, Windows Phone 8 App, C#.NET, XAML
mailto:[email protected]:[email protected]:[email protected]:[email protected]:[email protected]:[email protected]:[email protected]:[email protected]