Intersoft ClientUI Documentation
Walkthrough: Create Basic Navigation Application using MVVM Pattern

This walkthrough shows how to create simple website navigation by adding new page, new button and how to link the new button to the new page.

In this walkthrough, you perform the following tasks:

Prerequisites

You need the following components to complete this walkthrough:

Creating a new ClientUI Advanced Navigation Application Project

The first step is to create a new ClientUI Advanced Navigation Application project using  Intersoft ClientUI Advanced Navigation Application project template in Visual Studio.

To create the ClientUI Advanced Navigation Application project

  1. Start Visual Studio 2010.
  2. Create a new ClientUI Advanced Navigation Application project named ClientUIAdvNavApp1 using Intersoft ClientUI Basic Navigation Application project template . To learn more, see Walkthrough: Create New Intersoft ClientUI Advanced Navigation Application Template.
  3. In project reference, add System.Xml.Linq.dll. This assembly is required to perform linq query to xml data.

Note that Intersoft ClientUI Basic Navigation Application project template does not provide MVVM-ready template. Therefore you need to several base classes first for your Model and ViewModel classes. To learn more how to create this base classes see MVVM Pattern Overview.

To add the data file

  1. In your project, create new folder with name Data.
  2. In Data folder, insert the data source from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI Samples\Intersoft.ClientUI.Samples.Assets\Data\ContactDataSource.xml.
  3. Click on the ContactDataSource.xml file and press F4 to open the Property Window. Change the Build Action property to Resources.

To add the resources file

  1. In your project, create new folder with name Assets.
  2. In Assets folder, create new folder with name Images.
  3. In Images folder, create new folder with name Photos.
  4. In Photos folder, copy the images from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI Samples\Intersoft.ClientUI.Samples.Assets\Images\Photos\].

Next, you will create the Contact model class that represent the data entity used in this walkthrough.

Creating Model Class

This section shows you how to create the Contact model class that represent the data entity used in this walkthrough. To create the Contact model class, see Walkthrough: Creating Model for Contact Data.

Next, you will create the view for your simple contact list application.

Creating the View

This section steps you through the process of creating the user interface for your simple contacts list application using ClientUI controls such as GlassLabel, ContentTransition and UXListBox.

To create the View

  1. In your project, locate Views folder.
  2. In Views folder, add new Intersoft UXPage with name ContactsList.xaml.
    For more information on how to add a new item in Visual Studio, see Walkthrough: Add New Item such as Page, Dialog Box and Window in VS 2010
  3. Open ContactsList.xaml.
  4. Add Intersoft DockPanel inside the LayotRoot Grid.
    Remove all of the default properties and set the Width property to 640.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel Width="640">
                
        </Intersoft:DockPanel>
    </Grid>
  5. Add GlassLabel control inside the DockPanel.
    Set the following properties to the GlassLabel control:
    Property Value
    Height 50
    FontSize 21
    Content My Contact

    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel Width="640" FillChildMode="Custom">
            <Intersoft:GlassLabel Content="My Contact" Height="50" FontSize="21" Intersoft:DockPanel.Dock="Top" />
        </Intersoft:DockPanel>
    </Grid>

  6. Add ContentTransition.
    Set the Intersoft:DockPanel.IsFillElement property to True.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel Width="640" FillChildMode="Custom">
            <Intersoft:GlassLabel Content="My Contact" Height="50" FontSize="21" Intersoft:DockPanel.Dock="Top" />
            <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
            </Intersoft:ContentTransition>
        </Intersoft:DockPanel>
    </Grid>
  7. Add UXListBox inside ContentTransition.
    Set the HorizontalScrollBarVisibility property to Disabled and the AllowReorderItem property to True.
    Remove the two predefined UXListBoxItem from UXListBox.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel Width="640" FillChildMode="Custom">
            <Intersoft:GlassLabel Content="My Contact" Height="50" FontSize="21" Intersoft:DockPanel.Dock="Top" />
            <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
                <Intersoft:UXListBox Name="uXListBox1" HorizontalScrollBarVisibility="Disabled" AllowReorderItem="True">
                </Intersoft:UXListBox>
            </Intersoft:ContentTransition>
        </Intersoft:DockPanel>
    </Grid>
  8. Create a new DataTemplate for with name ContactsViewTemplate and put it in Intersoft:UXPage.Resources.
    XAML
    Copy Code
    <Intersoft:UXPage.Resources>
        <DataTemplate x:Key="ContactViewTemplate">
            <Grid Height="106">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="74"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Intersoft:ContentReflector HorizontalAlignment="Left" VerticalAlignment="Top" ContentHeight="64">
                    <Image/>
                </Intersoft:ContentReflector>
                <StackPanel Grid.Column="1" HorizontalAlignment="Left" Orientation="Vertical" VerticalAlignment="Top" Margin="0,7,0,0">
                    <TextBlock d:LayoutOverrides="Width" Foreground="#FF838383" Margin="0,3"/>
                    <TextBlock d:LayoutOverrides="Width" Margin="0,3"/>
                    <TextBlock Margin="0,3"/>
                </StackPanel>
                <Border Grid.Column="1" HorizontalAlignment="Left" Margin="250,5,10,10" VerticalAlignment="Center" Width="300" Padding="10" CornerRadius="8" Background="#7FEBEBEB">
                    <StackPanel Orientation="Vertical" Height="86">
                        <Intersoft:UXHyperlinkButton BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/0161-write_email.png" IsToggleButton="False" ToolTipService.ToolTip="Email this contact." HorizontalAlignment="Left"/>
                        <Intersoft:UXHyperlinkButton BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/twitter.png" IsToggleButton="False" ToolTipService.ToolTip="See latest Twitter updates." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                        <Intersoft:UXHyperlinkButton BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/5000-web.png" IsToggleButton="False" ToolTipService.ToolTip="Visit the website." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                    </StackPanel>
                </Border>
                <Intersoft:UXSeparator VerticalAlignment="Bottom" Grid.ColumnSpan="2" Background="#FFD8D8D8"/>
            </Grid>
        </DataTemplate>
    </Intersoft:UXPage.Resources>
  9. Set the ItemTemplate property of UXListBox to {StaticResource ContactViewTemplate}, the data template you just created in the previous step.
    XAML
    Copy Code
    ...
    <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:UXListBox Name="uXListBox1" HorizontalScrollBarVisibility="Disabled" AllowReorderItem="True" ItemTemplate="{StaticResource ContactViewTemplate}">
        </Intersoft:UXListBox>
    </Intersoft:ContentTransition>
    ...
  10. Add Border control to DockPanel.
    Set the Intersoft:DockPanel.Dock property to Bottom, the Height property to 30 and the Background property to #FF2A2A2A.
    XAML
    Copy Code
    ...
    <Intersoft:DockPanel Width="640" FillChildMode="Custom">
        <Intersoft:GlassLabel Content="My Contact" Height="50" FontSize="21" Intersoft:DockPanel.Dock="Top" />
        <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
            <Intersoft:UXListBox Name="uXListBox1" HorizontalScrollBarVisibility="Disabled" AllowReorderItem="True" ItemTemplate="{StaticResource ContactViewTemplate}">
            </Intersoft:UXListBox>
        </Intersoft:ContentTransition>
        <Border BorderBrush="Silver" Height="30" Name="border1" Intersoft:DockPanel.Dock="Bottom" Background="#FF2A2A2A">
        </Border>
    </Intersoft:DockPanel>
    ...
  11. Add StackPanel to Border.
    Set the Orientation property to Horizontal and the HorizontalAlignment property to Center.
    XAML
    Copy Code
    ...
    <Border BorderBrush="Silver" Height="30" Name="border1" Intersoft:DockPanel.Dock="Bottom" Background="#FF2A2A2A">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        </StackPanel>
    </Border>
    ...
  12. Add TextBlock control to StackPanel.
    Set the Foreground property to White and the VerticalAlignment property to Center.
    XAML
    Copy Code
    ...
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <TextBlock Foreground="White" VerticalAlignment="Center"/>
    </StackPanel>
    ...
  13. Add UXSeparator control to StackPanel.
    Set the following properties:
    Property Value
    Orientation Vertical
    Height 16
    Width 1
    Margin 10,0

    XAML
    Copy Code
    ...
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <TextBlock Foreground="White" VerticalAlignment="Center"/>
        <Intersoft:UXSeparator Orientation="Vertical" Height="16" Width="1" Margin="10,0"/>
    </StackPanel>
    ...
  14. Add TextBlock control to StackPanel.
    Set the Foreground property to White and the VerticalAlignment property to Center.
    XAML
    Copy Code
    ...
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <TextBlock Foreground="White" VerticalAlignment="Center"/>
        <Intersoft:UXSeparator Orientation="Vertical" Height="16" Width="1" Margin="10,0"/>
        <TextBlock Foreground="White" VerticalAlignment="Center" />
    </StackPanel>
    ...
  15. Here is the final screen shot of the View.

Next, you will create the ViewModel that describe the View you just created.

Creating the ViewModel

In the ContactsList.xaml page you just created, there are some UXHyperLinkButton declared in the ItemTemplate that going to be directed to an external uri provided by Twitter, Blog and Email properies in the Contact model.

In order for the UXHyperLinkButton to work properly, the format for email uri must be "mail-to: [email address]". Since Contact model only provides the email address, you need to extend the Contact model to ContactView model that has extended property such as EmailUri along with the original Contact reference.

To create the ContactViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name ContactViewModel.
  3. At ContactViewModel, inherit the ContactViewModel class from ViewModelBase class.
    C#
    Copy Code
    public class ContactViewModel : ViewModelBase
    {
    }
  4. In ContactViewModel, create the EmailUri and Contact property along with constructor to that accept the Contact model as its parameter.
    C#
    Copy Code
    public class ContactViewModel : ViewModelBase
    {
        // Fields
        private Contact _contact;
    
        // Constructor
        public ContactViewModel(Contact contact)
        {
            _contact = contact;
        }
    
        // Views
        public Contact Contact
        {
            get { return this._contact; }
        }
    
        public string EmailUri
        {
            get { return "mailto:" + _contact.Email; }
        }
    }

Next, you will create the ContactsListViewModel that describes the ContactsList.xaml page.

You will create four properties in ContactsListViewModel to be used in the ContactList.xaml page such as described in the following list.

To create the ContactsListViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name ContactsListViewModel.
  3. At ContactsListViewModel, inherit the ContactsListViewModel class from ViewModelBase class.
    C#
    Copy Code
    public class ContactsListViewModel : ViewModelBase
    {
    }
  4. In ContactsListViewModel, add the Contacts, ContactsCount, SelectedItem and SelectionStatus properties along with a LoadContacts method to extract the data from the xml file.
    C#
    Copy Code
    public class ContactsListViewModel : ViewModelBase
    {
        #region Constructor
    
        public ContactsListViewModel()
        {
            this.LoadContacts();
            this.Contacts.CollectionChanged += new NotifyCollectionChangedEventHandler(Contacts_CollectionChanged);
        }
    
        #endregion
        
        #region Fields
    
        private ContactViewModel _selectedItem = null;
    
        #endregion
               
        #region Properties
    
        public ObservableCollection<ContactViewModel> Contacts { get; set; }
    
        public string ContactsCount
        {
            get
            {
                if (this.Contacts.Count == 0)
                    return "No contacts";
                else if (this.Contacts.Count == 1)
                    return "1 contact";
                else
                    return this.Contacts.Count + " contacts";
            }
        }
    
    
        public ContactViewModel SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    if (_selectedItem != null)
                        _selectedItem.Contact.PropertyChanged -= new PropertyChangedEventHandler(Contact_PropertyChanged);
                    
                    if (value != null)
                        value.Contact.PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);
    
                    _selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                    OnPropertyChanged("SelectionStatus");
                }
            }
        }
    
    
        public string SelectionStatus
        {
            get
            {
                if (this.SelectedItem == null)
                    return "No contact selected";
                else
                    return "Selected contact: " + this.SelectedItem.Contact.Name;
            }
        }
    
        #endregion
    
        #region Methods
    
        private void LoadContacts()
        {
            // loads contact data from xml file
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
                    new Uri("MVVMApplicationWalkthrough;component/App_Data/ContactDataSource.xml", UriKind.Relative));
    
            XDocument doc = XDocument.Load(resource.Stream);
    
            var contacts = from x in doc.Descendants("Customer")
                            select new Contact(x);
    
            this.Contacts = new ObservableCollection<ContactViewModel>();
    
            foreach (Contact contact in contacts)
            {
                contact.SetPhoto(this.Contacts.Count.ToString());
                this.Contacts.Add(new ContactViewModel(contact));
            }
    
            resource.Stream.Close();
        }
    
        private void Contact_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Name")
                OnPropertyChanged("SelectionStatus");
        }
    
        private void Contacts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("ContactsCount");
        }
    
        #endregion
    }

Next, you will bind the ContactsListViewModel to your ContactsList.xaml.

Binding the View to ViewModel

In the previous sections, you have learned how to create the Model and ViewModel clases, as well as the View that contains the user interface and controls used in this walkthrough. This sections shows how to instantiate the ContactsListViewModel in the ContactsList.xaml page and bind the UI elements to the properties in the ContactsListViewModel such as Contacts and SelectedItem.

To bind the ContactsListViewModel to ContactsList.xaml page

  1. In ContactsList.xaml, add the following mark up to instantiate ContactsListViewModel in ContactList.xaml page.
    XAML
    Copy Code
    <Intersoft:UXPage.DataContext>
        <ViewModels:ContactsListViewModel />
    </Intersoft:UXPage.DataContext>
  2. In ContactsList.xaml, locate the UXListBox under ContentTransition.
  3. Bind the ItemsSource property of the UXListBox to {Binding Contacts} and SelectedItem property to {Binding SelectedItem, Mode=TwoWay}.

    XAML
    Copy Code
    ...
    <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:UXListBox ItemsSource="{Binding Contacts}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Name="uXListBox1" HorizontalScrollBarVisibility="Disabled" AllowReorderItem="True" ItemTemplate="{StaticResource ContactViewTemplate}">
        </Intersoft:UXListBox>
    </Intersoft:ContentTransition>
    ...


  4. In ContactsList.xaml, locate the ContactViewTemplate inside UXPage.Resources.
  5. Bind the controls inside DataTemplate such as Image, TextBlock and UXHyperlinkButton to specific properties from ContactViewModel such as shown in the following example.
    XAML
    Copy Code
    ...
    <DataTemplate x:Key="ContactViewTemplate">
        <Grid Height="106">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="74"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Intersoft:ContentReflector HorizontalAlignment="Left" VerticalAlignment="Top" ContentHeight="64">
                <Image Source="{Binding Contact.Photo}"/>
            </Intersoft:ContentReflector>
            <StackPanel Grid.Column="1" HorizontalAlignment="Left" Orientation="Vertical" VerticalAlignment="Top" Margin="0,7,0,0">
                <TextBlock d:LayoutOverrides="Width" Foreground="#FF838383" Margin="0,3" Text="{Binding Contact.Id}"/>
                <TextBlock d:LayoutOverrides="Width" Margin="0,3" Text="{Binding Contact.Name}"/>
                <TextBlock Margin="0,3" Text="{Binding Contact.Phone}"/>
            </StackPanel>
            <Border Grid.Column="1" HorizontalAlignment="Left" Margin="250,5,10,10" VerticalAlignment="Center" Width="300" Padding="10" CornerRadius="8" Background="#7FEBEBEB">
                <StackPanel Orientation="Vertical" Height="86">
                    <Intersoft:UXHyperlinkButton Content="{Binding Contact.Email}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/0161-write_email.png" NavigateUri="{Binding Contact.Email}" IsToggleButton="False" ToolTipService.ToolTip="Email this contact." HorizontalAlignment="Left"/>
                    <Intersoft:UXHyperlinkButton Content="{Binding Contact.Twitter}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/twitter.png" NavigateUri="{Binding Contact.Twitter}" IsToggleButton="False" ToolTipService.ToolTip="See latest Twitter updates." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                    <Intersoft:UXHyperlinkButton Content="{Binding Contact.Website}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/5000-web.png" NavigateUri="{Binding Contact.Website}" IsToggleButton="False" ToolTipService.ToolTip="Visit the website." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                </StackPanel>
            </Border>
            <Intersoft:UXSeparator VerticalAlignment="Bottom" Grid.ColumnSpan="2" Background="#FFD8D8D8"/>
        </Grid>
    </DataTemplate>
    ...


    Try to rebuild the project, if there is no data shown after binding.
  6. Bind the TextBlock controls in the footer area to display number of contacts available and selection status information from the ViewModel through the provided properties, such as shown in the following example
    XAML
    Copy Code
    ...
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <TextBlock Foreground="White" VerticalAlignment="Center" Text="{Binding ContactsCount}"/>
        <Intersoft:UXSeparator Orientation="Vertical" Height="16" Width="1" Margin="10,0"/>
        <TextBlock Foreground="White" VerticalAlignment="Center" Text="{Binding SelectionStatus}" />
    </StackPanel>
    ...

  7. Save, build and run the project.

Creating a New Navigation Button

This section shows how to create a new navigation button using UXNavigationButton and set the NavigationUri to ContactsList.xaml page you just created in the previous section.

To create the Contact List navigation button

  1. Open MainPage.xaml.
  2. Add new UXNavigationButton after About button.
    Set the following properties:
    Property Value
    x:Name btnContactsList
    Content Contacts List
    NavigateUri /ContactsList
    Icon Assets/Images/Contact.png

    XAML
    Copy Code
    <Grid Intersoft:DockPanel.Dock="Bottom">
        <Intersoft:UXItemsControl x:Name="NavigationItemsContainer" ItemContainerStyle="{StaticResource NavigationButtonStyle}" Orientation="Horizontal" Background="{StaticResource NavigationContainerBackground}">
            <Intersoft:UXNavigationButton x:Name="btnHome" Content="Home" NavigateUri="/Home" Icon="Assets/Images/Home.png" IsDefaultNavigationSource="True"/>
            <Intersoft:UXNavigationButton Content="Customers" NavigateUri="/Customers" Icon="Assets/Images/CustomersFolder.png"/>
            <Intersoft:UXNavigationButton Content="Products" NavigateUri="/Products" Icon="Assets/Images/Products.png"/>
            <Intersoft:UXNavigationButton Content="Reports" NavigateUri="/Reports" Icon="Assets/Images/Reports.png"/>
            <Intersoft:UXNavigationButton Content="Settings" NavigateUri="/Settings" Icon="Assets/Images/Settings.png"/>
            <Intersoft:UXNavigationButton Content="About" NavigateUri="/About" Icon="Assets/Images/ClientUI_Silverlight.png"/>
            <Intersoft:UXNavigationButton x:Name="btnContactsList" Content="Contacts List" NavigateUri="/ContactList" Icon="Assets/Images/Contact.png"/>
        </Intersoft:UXItemsControl>    ... 
    </Grid>

  3. Save, build and run the project.
    Click on the Contacts List button to navigate to the Contacts List page.

Conclusion

In this walkthrough, you have learned how to create ClientUI Advanced Navigation Application project using Intersoft ClientUI AdvancedNavigation Application project template, and also creating a new page along with the button to navigate to the new page.

You have also learned how to create classes and page based on the MVVM pattern. For more information about application development using MVVM pattern, see MVVM Pattern Overview. For more information about navigation framework and its concepts, see Navigation Overview.

Complete Code Listing

This section lists the complete code used in this walkthrough.

Contact.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using MVVMApplicationWalkthrough.ViewModels;
using System.ComponentModel;
using System.Xml.Linq;

namespace MVVMApplicationWalkthrough.Models
{
    public class Contact : ModelBase
    {        
        #region Constructors

        public Contact()
        {
        }

        public Contact(XElement x)
            : this()
        {
            this._id = x.Element("Id").Value.Trim();
            this._name = x.Element("Name").Value.Trim();
            this._email = x.Element("Email").Value.Trim();

            this._address = x.Element("Address").Value.Trim();
            this._state = x.Element("State").Value.Trim();
            this._zipCode = x.Element("ZipCode").Value.Trim();

            this._phone = x.Element("Phone").Value.Trim();
            this._fax = x.Element("Fax").Value.Trim();
            this._cell = x.Element("Cell").Value.Trim();

            this._blog = x.Element("Blog").Value.Trim();
            this._twitter = x.Element("Twitter").Value.Trim();
            this._website = x.Element("Website").Value.Trim();
        }

        #endregion

        #region Fields

        private string _name = string.Empty;
        private string _address = string.Empty;
        private string _phone = string.Empty;
        private string _cell = string.Empty;
        private string _id = string.Empty;
        private string _email = string.Empty;
        private string _fax = string.Empty;
        private string _blog = string.Empty;
        private string _twitter = string.Empty;
        private string _website = string.Empty;
        private string _state = string.Empty;
        private string _zipCode = string.Empty;
        private Uri _photo = null;

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                return this._name;
            }

            set
            {
                if (this._name != value)
                {
                    this._name = value;
                    this.ClearError("Name");
                    this.OnPropertyChanged("Name");
                }
            }
        }

        public string Address
        {
            get
            {
                return this._address;
            }

            set
            {
                if (this._address != value)
                {
                    this._address = value;
                    this.ClearError("Address");
                    this.OnPropertyChanged("Address");
                }
            }
        }

        public string Phone
        {
            get
            {
                return this._phone;
            }

            set
            {
                if (this._phone != value)
                {
                    this._phone = value;
                    this.OnPropertyChanged("Phone");
                }
            }
        }

        public string Cell
        {
            get
            {
                return this._cell;
            }

            set
            {
                if (this._cell != value)
                {
                    this._cell = value;
                    this.OnPropertyChanged("Cell");
                }
            }
        }

        public string Id
        {
            get
            {
                return this._id;
            }

            set
            {
                if (this._id != value)
                {
                    this._id = value;
                    this.OnPropertyChanged("Id");
                }
            }
        }

        public string Email
        {
            get
            {
                return this._email;
            }

            set
            {
                if (this._email != value)
                {
                    this._email = value;
                    this.OnPropertyChanged("Email");
                }
            }
        }

        public string Fax
        {
            get
            {
                return this._fax;
            }

            set
            {
                if (this._fax != value)
                {
                    this._fax = value;
                    this.OnPropertyChanged("Fax");
                }
            }
        }

        public string Blog
        {
            get
            {
                return this._blog;
            }

            set
            {
                if (this._blog != value)
                {
                    this._blog = value;
                    this.OnPropertyChanged("Blog");
                }
            }
        }

        public string Twitter
        {
            get
            {
                return this._twitter;
            }

            set
            {
                if (this._twitter != value)
                {
                    this._twitter = value;
                    this.OnPropertyChanged("Twitter");
                }
            }
        }

        public string Website
        {
            get
            {
                return this._website;
            }

            set
            {
                if (this._website != value)
                {
                    this._website = value;
                    this.OnPropertyChanged("Website");
                }
            }
        }

        public string State
        {
            get
            {
                return this._state;
            }

            set
            {
                if (this._state != value)
                {
                    this._state = value;
                    this.OnPropertyChanged("State");
                }
            }
        }

        public string ZipCode
        {
            get
            {
                return this._zipCode;
            }

            set
            {
                if (this._zipCode != value)
                {
                    this._zipCode = value;
                    this.ClearError("ZipCode");
                    this.OnPropertyChanged("ZipCode");
                }
            }
        }

        public Uri Photo
        {
            get
            {
                return this._photo;
            }

            set
            {
                if (this._photo != value)
                {
                    this._photo = value;
                    this.OnPropertyChanged("Photo");
                }
            }

        }

        #endregion

        #region Methods

        public void SetPhoto(string uri)
        {
            this.Photo = new Uri("/Intersoft.ClientUI.Samples;component/Assets/Images/Photos/" + uri + ".jpg", UriKind.RelativeOrAbsolute);
        }  

        #endregion

    }
}

ContactsList.xaml

XAML
Copy Code
<Intersoft:UXPage 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
    xmlns:ViewModels="clr-namespace:MVVMApplicationWalkthrough.ViewModels"
        mc:Ignorable="d"
        x:Class="MVVMApplicationWalkthrough.Views.ContactsList" 
        Title="ContactsList Page"
        d:DesignWidth="640" d:DesignHeight="480" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
        
    <Intersoft:UXPage.DataContext>
        <ViewModels:ContactsListViewModel />
    </Intersoft:UXPage.DataContext>
    
    <Intersoft:UXPage.Resources>
        <DataTemplate x:Key="ContactViewTemplate">
            <Grid Height="106">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="74"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Intersoft:ContentReflector HorizontalAlignment="Left" VerticalAlignment="Top" ContentHeight="64">
                    <Image Source="{Binding Contact.Photo}"/>
                </Intersoft:ContentReflector>
                <StackPanel Grid.Column="1" HorizontalAlignment="Left" Orientation="Vertical" VerticalAlignment="Top" Margin="0,7,0,0">
                    <TextBlock d:LayoutOverrides="Width" Foreground="#FF838383" Margin="0,3" Text="{Binding Contact.Id}"/>
                    <TextBlock d:LayoutOverrides="Width" Margin="0,3" Text="{Binding Contact.Name}"/>
                    <TextBlock Margin="0,3" Text="{Binding Contact.Phone}"/>
                </StackPanel>
                <Border Grid.Column="1" HorizontalAlignment="Left" Margin="250,5,10,10" VerticalAlignment="Center" Width="300" Padding="10" CornerRadius="8" Background="#7FEBEBEB">
                    <StackPanel Orientation="Vertical" Height="86">
                        <Intersoft:UXHyperlinkButton Content="{Binding Contact.Email}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/0161-write_email.png" NavigateUri="{Binding Email}" IsToggleButton="False" ToolTipService.ToolTip="Email this contact." HorizontalAlignment="Left"/>
                        <Intersoft:UXHyperlinkButton Content="{Binding Contact.Twitter}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/twitter.png" NavigateUri="{Binding Twitter}" IsToggleButton="False" ToolTipService.ToolTip="See latest Twitter updates." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                        <Intersoft:UXHyperlinkButton Content="{Binding Contact.Website}" BorderThickness="0" DisplayMode="ContentAndImage" Icon="/MVVMApplicationWalkthrough;component/Assets/Icons/5000-web.png" NavigateUri="{Binding Website}" IsToggleButton="False" ToolTipService.ToolTip="Visit the website." HorizontalAlignment="Left" TargetName="_blank" ShowUnderlineOnHover="False"/>
                    </StackPanel>
                </Border>
                <Intersoft:UXSeparator VerticalAlignment="Bottom" Grid.ColumnSpan="2" Background="#FFD8D8D8"/>
            </Grid>
        </DataTemplate>
    </Intersoft:UXPage.Resources>
    
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel Width="640" FillChildMode="Custom">
            <Intersoft:GlassLabel Content="My Contact" Height="50" FontSize="21" Intersoft:DockPanel.Dock="Top" />
                <Intersoft:ContentTransition Intersoft:DockPanel.IsFillElement="True">
                <Intersoft:UXListBox ItemsSource="{Binding Contacts}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Name="uXListBox1" HorizontalScrollBarVisibility="Disabled" AllowReorderItem="True" ItemTemplate="{StaticResource ContactViewTemplate}">
                    </Intersoft:UXListBox>
                </Intersoft:ContentTransition>
            <Border BorderBrush="Silver" Height="30" Name="border1" Intersoft:DockPanel.Dock="Bottom" Background="#FF2A2A2A">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                    <TextBlock Foreground="White" VerticalAlignment="Center" Text="{Binding ContactsCount}"/>
                    <Intersoft:UXSeparator Orientation="Vertical" Height="16" Width="1" Margin="10,0"/>
                    <TextBlock Foreground="White" VerticalAlignment="Center" Text="{Binding SelectionStatus}" />
                </StackPanel>
            </Border>
        </Intersoft:DockPanel>
    </Grid>
</Intersoft:UXPage>

ContactViewModel.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using MVVMApplicationWalkthrough.Models;

namespace MVVMApplicationWalkthrough.ViewModels
{
    public class ContactViewModel : ViewModelBase
    {
        // Fields
        private Contact _contact;

        // Constructor
        public ContactViewModel(Contact contact)
        {
            _contact = contact;
        }

        // Views
        public Contact Contact
        {
            get { return this._contact; }
        }

        public string EmailUri
        {
            get { return "mailto:" + _contact.Email; }
        }
    }
}

ContactsListViewModel.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Intersoft.Client.Framework.Input;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Windows.Resources;
using System.Xml.Linq;
using System.Linq;
using MVVMApplicationWalkthrough.Models;

namespace MVVMApplicationWalkthrough.ViewModels
{
    public class ContactsListViewModel : ViewModelBase
    {
        #region Constructor

        public ContactsListViewModel()
        {
            this.LoadContacts();
            this.Contacts.CollectionChanged += new NotifyCollectionChangedEventHandler(Contacts_CollectionChanged);
        }

        #endregion
        
        #region Fields

        private ContactViewModel _selectedItem = null;

        #endregion
               
        #region Properties

        public ObservableCollection<ContactViewModel> Contacts { get; set; }

        public string ContactsCount
        {
            get
            {
                if (this.Contacts.Count == 0)
                    return "No contacts";
                else if (this.Contacts.Count == 1)
                    return "1 contact";
                else
                    return this.Contacts.Count + " contacts";
            }
        }


        public ContactViewModel SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    if (_selectedItem != null)
                        _selectedItem.Contact.PropertyChanged -= new PropertyChangedEventHandler(Contact_PropertyChanged);
                    
                    if (value != null)
                        value.Contact.PropertyChanged += new PropertyChangedEventHandler(Contact_PropertyChanged);

                    _selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                    OnPropertyChanged("SelectionStatus");
                }
            }
        }


        public string SelectionStatus
        {
            get
            {
                if (this.SelectedItem == null)
                    return "No contact selected";
                else
                    return "Selected contact: " + this.SelectedItem.Contact.Name;
            }
        }

        #endregion

        #region Methods

        private void LoadContacts()
        {
            // loads contact data from xml file
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
                    new Uri("MVVMApplicationWalkthrough;component/Data/ContactDataSource.xml", UriKind.Relative));

            XDocument doc = XDocument.Load(resource.Stream);

            var contacts = from x in doc.Descendants("Customer")
                            select new Contact(x);

            this.Contacts = new ObservableCollection<ContactViewModel>();

            foreach (Contact contact in contacts)
            {
                contact.SetPhoto(this.Contacts.Count.ToString());
                this.Contacts.Add(new ContactViewModel(contact));
            }

            resource.Stream.Close();
        }

        private void Contact_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Name")
                OnPropertyChanged("SelectionStatus");
        }

        private void Contacts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            OnPropertyChanged("ContactsCount");
        }

        #endregion
    }
}
See Also

Concepts

Other Resources