Intersoft ClientUI Documentation
Walkthrough: Create Your First ClientUI Application using MVVM Pattern

This walkthrough shows how to create simple contacts list application using ClientUI and MVVM pattern. The following figure shows the result that you will achieve upon completing this walkthrough.

In this walkthrough, you perform the following tasks:

Prerequisites

You need the following components to complete this walkthrough:

Creating a new ClientUI MVVM Application Project

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

To create the ClientUI MVVM Application project

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

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 represents 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 contacts 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 several UXHyperLinkButton instances defined in the ItemTemplate used to navigate to an external URI provided by Twitter, Blog and Email properties in the Contact model.

In order for the UXHyperLinkButton to work properly, the format for email uri should be in the form of "mail-to: [email address]". Since Contact model only provide 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 class

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name ContactViewModel.
  3. In ContactViewModel.cs, 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, which are listed in the following:

To create the ContactsListViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name ContactsListViewModel.
  3. In ContactsListViewModel.cs, inherit the ContactsListViewModel from the 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 classes, 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.

Conclusion

In this walkthrough, you have learned how to create ClientUI MVVM Application project using Intersoft ClientUI MVVM Application project template, and create classes and page based on the MVVM pattern. You also learned how to bind UXListBox to a collection of data and how to use ItemTemplate to display the contact detail.

For more information about application development using MVVM pattern, see MVVM Pattern 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