Mvvm Tutorial

Embed Size (px)

Citation preview

  • 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.xml
  • 8/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]