Sunday, September 1, 2013

MVVM – Windows 8 Store App using XAML/C#.NET Primer

MVVM – Windows 8 Store App using XAML/C#.NET Primer
 
Purpose: The purpose of this document is to illustrate how to how to apply MVVM (Model-View-ViewModel) architectural pattern when developing Windows 8 Store Product catalog App using XAML/C#.NET
 
Challenge: You may need to develop a modern application integrated with Microsoft Dynamics AX 2012 for the purposes of demonstration, POC or to be deployed in production environment. The question is what technology and architectural pattern to use in order to facilitate application development and maintenance efforts    
 
Solution: In this scenario we'll leverage Windows 8 SDK which contains headers, libraries and tools you need for developing Windows 8 Store App using XAML/C#.NET
 
Walkthrough
 
First off let's create a new project using Visual C# > Windows Store > Blank App (XAML) template
 
New Project
 
 
Then we'll apply MVVM (Model-View-ViewModel) architectural pattern for development of Product catalog app
 
Solution Explorer
 
 
For the sake of clarity I created 3 folders for Model, View and ViewModel
 
The model encapsulates business logic and data. Please see below how I define Product class which has 2 attributes: ID and Name as a part of the model
 
Model
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace App1.Model
{
    public class Product
    {
        public string ID { get; set; }
        public string Name { get; set; }
    }
}
 
The view model encapsulates presentation logic and state. Please see below how I define ObservableCollection of products with respective method(s) (GetProducts) as a part of the view model
 
ViewModel
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.ComponentModel;
using System.Collections.ObjectModel;
using App1.Model;
 
namespace App1.ViewModel
{
    public class ProductViewModel
    {
        private ObservableCollection<Product> _Products = new ObservableCollection<Product>();
 
        public ObservableCollection<Product> Products
        {
            get
            {
                return _Products;
            }
            set
            {
                _Products = value;
            }
        }
 
        public async Task GetProducts()
        {
            Product product;
           
            product = new Product();
            product.ID = "X";
            product.Name = "AlexProductX";
            Products.Add(product);
        }
    }
 
}
 
The view encapsulates the UI and any UI logic. Please see below how I instantiate an object of view model class to retrieve a list of products
 
View (ProductsPage.xaml.cs)
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
 
using App1.Model;
using App1.ViewModel;
 
// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237
 
namespace App1
{
    public sealed partial class ProductsPage : App1.Common.LayoutAwarePage
    {
        public ProductsPage()
        {
            this.InitializeComponent();
        }
 
        protected override async void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            ProductViewModel productViewModel = new ProductViewModel();
            productViewModel.GetProducts();
            this.pageRoot.DataContext = productViewModel;
        }
 
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }
    }
}
 
And then I use bindings to link product metadata to respective UI elements for display
 
XAML (ProductsPage.xaml)
 
<common:LayoutAwarePage
    x:Name="pageRoot"
    x:Class="App1.ProductsPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:common="using:App1.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
    <Page.Resources>
 
        <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
        <x:String x:Key="AppName">Product Catalog</x:String>
    </Page.Resources>
 
    <!--
        This grid acts as a root panel for the page that defines two rows:
        * Row 0 contains the back button and page title
        * Row 1 contains the rest of the page layout
    -->
    <Grid Style="{StaticResource LayoutRootStyle}">
        <Grid.RowDefinitions>
            <RowDefinition Height="140"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!-- Back button and page title -->
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
            <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}"/>
        </Grid>
       
        <GridView x:Name="ProductGridView" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Products}" Grid.Row="1"  Margin="80,20" ItemTemplate="{StaticResource ProductDataTemplate}"/>
       
        <VisualStateManager.VisualStateGroups>
 
            <!-- Visual states reflect the application's view state -->
            <VisualStateGroup x:Name="ApplicationViewStates">
                <VisualState x:Name="FullScreenLandscape"/>
                <VisualState x:Name="Filled"/>
 
                <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
                <VisualState x:Name="FullScreenPortrait">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
 
                <!-- The back button and title have different styles when snapped -->
                <VisualState x:Name="Snapped">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Grid>
</common:LayoutAwarePage>
 
Please note that I used ItemTemplate to define a style. You can easily generate ItemTemplate as shown below 
 
Document Outline
 
 
And then define a style for any UI element as you wish
 
Template (App.xaml)
 
<Application
    x:Class="App1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1">
 
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
 
                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <DataTemplate x:Key="ProductDataTemplate">
                <Grid Width="400" Height="100" Background="White">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="100"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>                       
                    </Grid.RowDefinitions>
                    <Border BorderThickness="2" BorderBrush="White" Height="100" VerticalAlignment="Top" Background="Black">
                        <TextBlock TextWrapping="Wrap" Text="{Binding ID}" Style="{StaticResource ItemTextStyle}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </Border>
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" Style="{StaticResource GroupHeaderTextStyle}" Margin="10,5,10,0" Grid.Column="1" Foreground="Black"/>                   
                </Grid>
            </DataTemplate>
 
        </ResourceDictionary>
    </Application.Resources>
</Application>
 
As the result our Product catalog application will look like below
 
Result
 
 
Please review the following article to learn how to quickly connect your application to Microsoft Dynamics AX 2012 Demo VM to test out the integration: http://ax2012aifintegration.blogspot.com/2013/04/microsoft-dynamics-ax-2012-windows-8.html
 
In case you are developing a mobile application for production please review the best practice guidance on Developing Mobile apps for Microsoft Dynamics AX 2012 here: http://www.microsoft.com/en-us/download/details.aspx?id=38413
 
Summary: This document describes how to apply MVVM (Model-View-ViewModel) architectural pattern when developing Windows 8 Store Product catalog sample App using XAML/C#.NET.
 
Author: Alex Anikiev, PhD, MCP
 
Tags: MVVM, Model-View-ViewModel, Windows 8 Store App, C#.NET, XAML, Microsoft Dynamics AX 2012.
 
Note: This document is intended for information purposes only, presented as it is with no warranties from the author. This document may be updated with more content to better outline the concepts and describe the examples.

No comments:

Post a Comment