Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

MVVM for Multi Platforms

, 22 Mar 2010
How to implement MVVM when developing a view model whose view implementation language is not certain
GeographicRepresentation.zip
GeographicRepresentation
bin
Release
GeographicRepresentation.Interfaces.dll
GeographicRepresentation.Interfaces.pdb
GeographicRepresentation.Lib.dll
GeographicRepresentation.Lib.pdb
GeographicRepresentation.TestLib.dll
GeographicRepresentation.TestLib.pdb
GeographicRepresentation.UILib.exe
GeographicRepresentation.UILib.pdb
GeographicRepresentation.UILib.vshost.exe
GeographicRepresentation.UILib.vshost.exe.manifest
Resources
GeographicRepresentation.suo
GeographicRepresentation.TestLib
bin
Debug
GeographicRepresentation.Interfaces.dll
GeographicRepresentation.Lib.dll
GeographicRepresentation.TestLib.dll
Release
Properties
GeographicRepresentation.vsmdi
Interfaces
bin
Debug
GeographicRepresentation.Interfaces.dll
Release
Properties
Lib
bin
Debug
GeographicRepresentation.Interfaces.dll
GeographicRepresentation.Lib.dll
Release
Model
Properties
Resources
ViewModel
LocalTestRun.testrunconfig
TestResults
UILib
bin
Debug
GeographicRepresentation.UILib.exe
WpfApplication1.vshost.exe.manifest
Release
GeographicRepresentation.UILib.vshost.exe.manifest
Properties
Settings.settings
UILib.csproj.user
View
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using GeographicRepresentation.Interfaces;
using GeographicRepresentation.Lib;

namespace GeographicRepresentation.TestLib
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class ViewModelTests
    {
        public ViewModelTests()
        {

            string strDest = string.Format("{0}\\{1}", System.IO.Directory.GetCurrentDirectory(), DataManager.DATA_FILE_NAME);
            string strSource = string.Format("{0}\\..\\..\\..\\Lib\\{1}", System.IO.Directory.GetCurrentDirectory(), DataManager.DATA_FILE_NAME);
            System.IO.Directory.CreateDirectory(string.Format("{0}\\{1}", System.IO.Directory.GetCurrentDirectory(), "Resources"));
            System.IO.File.Copy(strSource, strDest, true);

            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion        

        AutoResetEvent m_Event = new AutoResetEvent(false);
        bool m_bOperationResult;
        

        [TestMethod]
        public void TestCreateAndEditCity()
        {            
            IEditableCityViewModel addVm = InterfacesFactory.Instance.GetEditableCityViewModelForAdd(DataManager.Instance.GetAllContinents().First(c => c.Countries.Count > 0).Countries.First().Id);
            Random r = new Random();

            addVm.CityName = "New York";
            addVm.Population = 	8363710 + r.Next(1000);
            addVm.TimeZone = -5;
            addVm.OnSaveCompleted += this.OperationSaveCompleted;

            int nTime = addVm.GetCurrentTime().Hour;
            addVm.TimeZone++;
            Assert.IsTrue(addVm.GetCurrentTime().Hour == nTime + 1, "Time zone not changed");

            m_bOperationResult = false;         
            
            SimpleOperationDelegate operation = new SimpleOperationDelegate(addVm.Save);            
            operation.BeginInvoke(this.OperationCompleted, operation);
            
            bool b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            // If the save operation succeeded, take the data for edit
            if (m_bOperationResult)
            {
                IEditableCityViewModel editVm = InterfacesFactory.Instance.GetEditableCityViewModelForEdit(addVm.Id);
                Assert.IsTrue(editVm.CityName == editVm.CityName, "City name was not saved");
                Assert.IsTrue(editVm.Population == editVm.Population, "Population was not saved");
                Assert.IsTrue(editVm.TimeZone == editVm.TimeZone, "Time zone was not saved");
                editVm.CityName = DateTime.Now.ToString();
                editVm.Population = DateTime.Now.Second;
                editVm.TimeZone = (short)DateTime.Now.Minute;
                // The call for cancel can be done syncronosly 
                editVm.Cancel();
                Assert.IsTrue(editVm.CityName == editVm.CityName, "City name was not changed in cancelation");
                Assert.IsTrue(editVm.Population == editVm.Population, "Population was not changed in cancelation");
                Assert.IsTrue(editVm.TimeZone == editVm.TimeZone, "Time zone was not changed in cancelation");
            }
        }

        private void OperationSaveCompleted(bool bSuccess)
        {
            m_bOperationResult = bSuccess;
        }

        private void OperationCompleted(IAsyncResult result)
        {
            m_Event.Set();
            if (result.IsCompleted)
            {
                SimpleOperationDelegate operation = result.AsyncState as SimpleOperationDelegate;
                Assert.IsNotNull(operation, "Invalid object returned to callback");
                operation.EndInvoke(result);
            }
        }

        [TestMethod]
        public void TestCreateAndEditCountry()
        {
            IEditableCountryViewModel addVm = InterfacesFactory.Instance.GetEditableCountryViewModelForAdd(DataManager.Instance.GetAllContinents().First().Id);
            addVm.CountryName = "France";
            addVm.Size = 674843;            
            addVm.BirthRate = 2.02f;
            m_Event = new AutoResetEvent(false);
            m_bOperationResult = false;
            SimpleOperationDelegate operation = new SimpleOperationDelegate(addVm.Save);
            operation.BeginInvoke(this.OperationCompleted, operation);
            bool b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            // If the save operation succeeded, take the data for edit
            if (m_bOperationResult)
            {
                IEditableCountryViewModel editVm = InterfacesFactory.Instance.GetEditableCountryViewModelForEdit(addVm.Id);
                Assert.IsTrue(addVm.CountryName == editVm.CountryName, "Name wasn't saved");
                Assert.IsTrue(addVm.Size == editVm.Size, "Size wasn't saved");
                Assert.IsTrue(addVm.BirthRate == editVm.BirthRate, "Birth rate wasn't saved");
                editVm.CountryName = DateTime.Now.ToString();
                editVm.Size = DateTime.Now.Minute;
                editVm.BirthRate = (float)(DateTime.Now.Ticks / 2.54);
                // The call for cancel can be done syncronosly 
                editVm.Cancel();                
                Assert.IsTrue(addVm.CountryName == editVm.CountryName, "Name wasn't changed in cancelation");
                Assert.IsTrue(addVm.Size == editVm.Size, "Size wasn't changed in cancelation");
                Assert.IsTrue(addVm.BirthRate == editVm.BirthRate, "Birth rate wasn't changed in cancelation");
            }            
        }

        [TestMethod]
        public void TestCreateAndEditContinent()
        {
            IEditableContinentViewModel addVm = InterfacesFactory.Instance.GetEditableContinentViewModelForAdd();
            addVm.ContinentName = "Asia";
            addVm.NumberOfCountries = 47;
            addVm.BestCityToBeIn = "Bangkok";            
            m_Event = new AutoResetEvent(false);
            m_bOperationResult = false;
            SimpleOperationDelegate operation = new SimpleOperationDelegate(addVm.Save);
            operation.BeginInvoke(this.OperationCompleted, operation);
            bool b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            // If the save operation succeeded, take the data for edit
            if (m_bOperationResult)
            {
                IEditableContinentViewModel editVm = InterfacesFactory.Instance.GetEditableContinentViewModelForEdit(addVm.Id);
                Assert.IsTrue(addVm.ContinentName == editVm.ContinentName, "Name wasn't saved");
                Assert.IsTrue(addVm.NumberOfCountries == editVm.NumberOfCountries, "Number of countreis wasn't saved");
                Assert.IsTrue(addVm.BestCityToBeIn == editVm.BestCityToBeIn, "Best city to be in wasn't saved");
                editVm.ContinentName = DateTime.Now.ToString();
                editVm.NumberOfCountries = DateTime.Now.Minute;
                editVm.BestCityToBeIn = DateTime.Now.ToString();
                // The call for cancel can be done syncronosly 
                editVm.Cancel();
                Assert.IsTrue(addVm.ContinentName == editVm.ContinentName, "Name wasn't changed in cancelation");
                Assert.IsTrue(addVm.NumberOfCountries == editVm.NumberOfCountries, "Number of countreis wasn't changed in cancelation");
                Assert.IsTrue(addVm.BestCityToBeIn == editVm.BestCityToBeIn, "Best city to be in wasn't changed in cancelation");
            }
        }

        private void DataChanged()
        {
            m_Event.Set();
        }

        /// <summary>
        /// A delegate for removing objects which is used in the following test
        /// </summary>
        /// <param name="obj"></param>
        internal delegate void RemoveObjectDelegate(IReadOnlyViewModel obj);

        [TestMethod]
        public void TestReadOnlyViewModels()
        {
            GeographicRepresentation.Lib.Model.Continent continent = DataManager.Instance.GetAllContinents().First();
            IContinentsListViewModel vm = InterfacesFactory.Instance.GetContinentsListViewModel();
            IReadOnlyContinentViewModel continentVm = vm.Continents.First(c => c.Id == continent.Id);
            continentVm.OnBestCityToBeInChanged += this.DataChanged;
            Assert.IsTrue(continentVm.Countries.Count == continent.Countries.Count, "Invalid number of countries in continent view model");
            bool b = false;
            try
            {                
                continentVm.NumberOfCountries = DateTime.Now.Second;                
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change number of countries");
            }            
            b = false;
            try
            {
                continentVm.ContinentName = DateTime.Now.ToString();
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change name");
            }            
            b = false;
            try
            {
                continentVm.BestCityToBeIn = DateTime.Now.ToString();
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change best city to live in");
            }
            GeographicRepresentation.Lib.Model.Country country = continent.Countries.First();
            IReadonlyCountryViewModel countryVm = continentVm.Countries.First(c => c.Id == country.Id);
            countryVm.OnBirthRateChanged += this.DataChanged;
            Assert.IsTrue(country.Cities.Count == countryVm.Cities.Count, "Invalid number of cities");
            b = false;
            try
            {
                countryVm.CountryName = DateTime.Now.ToString();
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change country name");
            }
            b = false;
            try
            {
                countryVm.Size = DateTime.Now.Second;
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change country size");
            }
            b = false;
            try
            {
                countryVm.BirthRate = (float)(DateTime.Now.Second / 1.01);
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change countries birth rate");
            }
            GeographicRepresentation.Lib.Model.City city = country.Cities.First();
            IReadOnlyCityViewModel cityVm = countryVm.Cities.First(c => c.Id == city.Id);
            b = false;
            try
            {
                cityVm.CityName = DateTime.Now.ToString();
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change city name");
            }
            b = false;
            try
            {
                cityVm.Population = DateTime.Now.Second;
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change city population");
            }
            b = false;
            try
            {
                cityVm.TimeZone = (short)DateTime.Now.Second;
            }
            catch
            {
                b = true;
            }
            if (!b)
            {
                Assert.Fail("Managed to change city time zone");
            }
            RemoveObjectDelegate delg = new RemoveObjectDelegate(vm.RemoveGeographicObject);
            delg.BeginInvoke(cityVm, new AsyncCallback(this.RemoveOperationCompleted), delg);
            b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            Assert.IsNull(country.Cities.FirstOrDefault(c => c.Id == city.Id), "Failed removing city from view model");
            delg = new RemoveObjectDelegate(vm.RemoveGeographicObject);
            delg.BeginInvoke(countryVm, new AsyncCallback(this.RemoveOperationCompleted), delg);
            b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            continent = DataManager.Instance.GetContinent(continent.Id);
            Assert.IsNull(continent.Countries.FirstOrDefault(c => c.Id == country.Id), "Failed removing country from view model");
            delg = new RemoveObjectDelegate(vm.RemoveGeographicObject);
            delg.BeginInvoke(continentVm, new AsyncCallback(this.RemoveOperationCompleted), delg);
            b = m_Event.WaitOne(WaitTimeManager.Interval);
            Assert.IsTrue(b, "Operation didn't complete");
            vm = InterfacesFactory.Instance.GetContinentsListViewModel();
            Assert.IsNull(vm.Continents.FirstOrDefault(c => c.Id == continent.Id), "Failed removing continent from view model");
        }

        private void RemoveOperationCompleted(IAsyncResult result)
        {
            m_Event.Set();
            if (result.IsCompleted)
            {
                RemoveObjectDelegate operation = result.AsyncState as RemoveObjectDelegate;
                Assert.IsNotNull(operation, "Invalid object returned to callback");
                operation.EndInvoke(result);
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Izhar Lotem
Software Developer
Israel Israel
Software Developer in a promising Clean-Tech company

| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 22 Mar 2010
Article Copyright 2010 by Izhar Lotem
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid