Intersoft ClientUI Documentation
Walkthrough: Create Contact Editing Form using MVVM Pattern

This walkthrough shows how to create to create the contact editing form to perform save action using MVVM pattern.

In this walkthrough, you perform the following tasks:

Prerequisites

You need the following components to complete this walkthrough:

Creating a new ClientUI MVVM Project

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

To create MVVM Application project

  1. Start Visual Studio 2010.
  2. Create a new Silverlight MVVM project using Intersoft ClientUI MVVM Application project template. To learn more, see Walkthrough: Create New Intersoft ClientUI MVVM Application Template.
  3. Add Data Folder to the Silverlight project.
  4. Add the ContactDataSource.xml (available in [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI 2010\Contacts_MVVM\SampleData) to the Silverlight project Data folder.
  5. Click on the ContactDataSource.xml file and press F4 to open the Property Window. Change the Build Action property to Resources.
  6. Add Assets folder to the Silverlight project.
  7. Add Icons folder that contains the icon's image from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI 2010\Contacts_MVVM\Assets to the Silverlight project Assets folder.
  8. Add Photos folder that contains contact's photo image from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI 2010\Contacts_MVVM\Assets to the Silverlight project Assets folder.
  9. Add System.Xml.Linq.dll as the silverlight project's reference. The System.Xml.Linq is required to perform LINQ query against XML data.

Creating Model Class

This section shows how to create the Contact model class that represents the data entity used in this walkthrough. The Contact model class contains methods such as SetPhoto to assign value to Photo property.

To create the StateCode Enum Class

  1. Create StateCode enum class. Add a new class to Models folder and named it State.cs.
    C#
    Copy Code
    namespace ClientUIMVVMApp2.Models
    {
        public enum StateCode
        {
            AL, // Alabama
            AK, // Alaska
            AS, // American Samoa
            AZ, // Arizona
            AR, // Arkansas
            CA, // California
            CO, // Colorado
            CT,
            DE,
            DC,
            FL,
            GA,
            GU,
            HI,
            ID,
            IL,
            IN,
            IA,
            KS,
            KY,
            LA,
            ME,
            MD,
            MH,
            MA,
            MI,
            FM,
            MN,
            MS,
            MO,
            MT,
            NE,
            NV,
            NH,
            NJ,
            NM,
            NY,
            NC,
            ND,
            MP,
            OH,
            OK,
            OR,
            PW,
            PA,
            PR,
            RI,
            SC,
            SD,
            TN,
            TX,
            UT,
            VT,
            VA,
            VI,
            WA,
            WV,
            WI,
            WY,
        }
    }

To create EnumDataProvider Class

This class is used as the StateCode enum collection.

  1. Create EnumDataProvider class for StateCode enum. Put it in Converter folder.
    C#
    Copy Code
    public abstract class EnumDataProvider<T>
    {
        IEnumerable _data;
    
        public IEnumerable Data
        {
            get
            {
                if (this._data == null)
                {
                    Type enumType = typeof(T);
                    List<object> list = new List<object>();
                    int value = 0;
    
                    while (Enum.IsDefined(enumType, value))
                    {
                        list.Add(Enum.ToObject(enumType, value));
                        value++;
                    }
    
                    this._data = list;
                }
    
                return this._data;
            }
        }
    }
    
    public sealed class StateCodeDataProvider : EnumDataProvider<StateCode>
    {
    }

To create the Contact Model Class

  1. Create a model class that inherit from ModelBase class under the Models folder, named it Contact.cs.
  2. Add Id property to the Contact model class by defining the backing field along with complete getter and setter in the property. In the setter property, you need to call the OnPropertyChanged method after the backing field is assigned to the new value.
    C#
    Copy Code
    private string _id;
    
    public string Id
    {
            get { return this._id; }
        set
        {
            if (this._id != value)
            {
                this._id = value;
                this.OnPropertyChanged("Id");
            }
        }
    }
  3. Also add Name, Email, Phone, Fax, Cell, Address, ZipCode, Blog, Twitter and Website property to the Contact model class by repeating step number 2.
    C#
    Copy Code
    private string _name;
    private string _email;
    private string _phone;
    private string _fax;
    private string _cell;
    private string _address;
    private string _zipCode;
    private string _blog;
    private string _twitter;
    private string _website;
    
    public string Name
    {
        get { return this._name; }
        set
        {
            if (this._name != value)
            {
                this._name = value;
                this.OnPropertyChanged("Name");
            }
        }
    }
    
    public string Email
    {
        get { return this._email; }
        set
        {
            if (this._email != value)
            {
                this._email = value;
                this.OnPropertyChanged("Email");
            }
        }
    }
    
    public string Phone
    {
        get { return this._phone; }
        set
        {
            if (this._phone != value)
            {
                this._phone = value;
                this.OnPropertyChanged("Phone");
            }
        }
    }
    
    public string Fax
    {
        get { return this._fax; }
        set
        {
            if (this._fax != value)
            {
                this._fax = value;
                this.OnPropertyChanged("Fax");
            }
        }
    }
    
    public string Cell
    {
        get { return this._cell; }
        set
        {
            if (this._cell != value)
            {
                this._cell = value;
                this.OnPropertyChanged("Cell");
            }
        }
    }
    
    public string Address
    {
        get { return this._address; }
        set
        {
            if (this._address != value)
            {
                this._address = value;
                this.OnPropertyChanged("Address");
            }
        }
    }
    
    public string ZipCode
    {
        get { return this._zipCode; }
        set
        {
            if (this._zipCode != value)
            {
                this._zipCode = value;
                this.OnPropertyChanged("ZipCode");
            }
        }
    }
    
    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");
            }
        }
    }
  4. Add StateCode property.
    C#
    Copy Code
    private StateCode _state;
    public StateCode State
    {
        get { return this._state; }
        set
        {
            if (this._state != value)
            {
                this._state = value;
                this.OnPropertyChanged("State");
            }
        }
    }
  5. Add Photo property.
    C#
    Copy Code
    private Uri _photo;
    
    public Uri Photo
    {
        get { return _photo; }
        set
        {
            if (this._photo != value)
            {
                _photo = value;
                OnPropertyChanged("Photo");
            }
        }
    }
  6. Add Constructors to the Contact model class.
    C#
    Copy Code
    private Contact(string id, string name, string email, string address, StateCode state, string zipCode, string phone, string cell, string fax, string blog, string twitter, string website, Uri photo)
    {
        this._id = id;
        this._name = name;
        this._email = email;
        this._address = address;
        this._state = state;
        this._zipCode = zipCode;
        this._phone = phone;
        this._cell = cell;
        this._fax = fax;
        this._blog = blog;
        this._twitter = twitter;
        this._website = website;
        this._photo = photo;
    }
    
    public Contact()
        : this(id: string.Empty, name: string.Empty, email: string.Empty, address: string.Empty, state: StateCode.AK, zipCode: string.Empty, phone: string.Empty, cell: string.Empty, fax: string.Empty, blog: string.Empty, twitter: string.Empty, website: string.Empty, photo: null)
    {
    }

Creating the View

This section steps you through the process of creating a page that uses a variety of ClientUI controls such as UXWindow, UXComboBox, ContentReflector, and ExpandableGroupBox. The UXComboBox is used to display a collection of StateCode, while the UXToolBarButton is used to execute the save and cancel action.

To Create the View

  1. Right click on Views folder, and add new item. Select Intersoft UXWindow as the template page. Name it EditClientProfile.xaml then click Add.
  2. Create Intersoft:UXWindow.PrimaryToolBarTemplate and put it before the Grid layout.
    In this steps, two UXToolBarButton will be created such as shown in the following sample.
    XAML
    Copy Code
    <Intersoft:UXWindow.PrimaryToolBarTemplate>
        <DataTemplate>
            <Grid>
                <Intersoft:UXToolBar Intersoft:DockPanel.Dock="Top" OverflowHandleVisibility="AsNeeded" Margin="0,8,0,0"
                                                                    GripHandleVisibility="Collapsed" HorizontalAlignment="Left">
                    <Intersoft:UXToolBar.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#90FFFFFF" Offset="0"/>
                            <GradientStop Color="#00B1D0E3" Offset="1"/>
                        </LinearGradientBrush>
                    </Intersoft:UXToolBar.Background>
                    <Intersoft:UXToolGroup>
                        <Intersoft:UXToolBarButton Content="Save" DisplayMode="Content" ToolTipService.ToolTip="Save Changes"/>
                        <Intersoft:UXSeparator/>
                        <Intersoft:UXToolBarButton Content="Cancel"  DisplayMode="Content" ToolTipService.ToolTip="Cancel Changes (Not implemented in this sample)"/>
                    </Intersoft:UXToolGroup>
                </Intersoft:UXToolBar>
            </Grid>
        </DataTemplate>
    </Intersoft:UXWindow.PrimaryToolBarTemplate>

  3. Add Grid layout inside the LayoutRoot.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Grid>
                
        </Grid>
    </Grid>
  4. Add DockPanel control inside the Grid layout. Clear the Intersoft DockPanel default properties and then set the FillChildMode to Custom.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Grid>
            <Intersoft:DockPanel FillChildMode="Custom">
                    
            </Intersoft:DockPanel>
        </Grid>
    </Grid>
  5. Add ContentReflector and set the following properties.
    Property Value
    Width 160
    HorizontalAlignment Left
    VerticalContentAlignment Bottom
    Margin 12

    XAML
    Copy Code
    ...
    <Intersoft:ContentReflector Name="contentReflector1" Width="160" HorizontalAlignment="Left" VerticalContentAlignment="Bottom" Margin="12">
        <Grid />
    </Intersoft:ContentReflector>
    ...
  6. Remove the Grid layout inside ContentReflector and replace it with Image control.
    XAML
    Copy Code
    ...
    <Intersoft:ContentReflector Name="contentReflector1" Width="160" HorizontalAlignment="Left" VerticalContentAlignment="Bottom" Margin="12">
        <Image />
    </Intersoft:ContentReflector>
    ...
  7. Add StackPanel control after ContentReflector. Set Intersoft:DockPanel.Dock to Right and Intersoft:DockPanel.IsFillElement to True.
    XAML
    Copy Code
    ...
    <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
    </StackPanel>
    ...
  8. Add ExpandableGroupBox control to StackPanel and set the Header to General and VerticalAlignment to Top.
    XAML
    Copy Code
    ...
    <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:ExpandableGroupBox Header="General Information" VerticalAlignment="Top" Name="expandableGroupBox1">
            <Grid Height="150" Width="200" />
        </Intersoft:ExpandableGroupBox>
    </StackPanel>
    ...

  9. Clear the content of ExpandableGroupBox. Replace it with UXItemControl and set the ItemContainerStyle to {StaticResource FieldLabelStyle}.
    XAML
    Copy Code
    ...
    <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:ExpandableGroupBox Header="General Information" VerticalAlignment="Top" Name="expandableGroupBox1">
            <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
            </Intersoft:UXItemsControl>
        </Intersoft:ExpandableGroupBox>
    </StackPanel>
    ...
  10. Now, create FieldLabelStyle as the UXWindow's resources. This is style that will be assiged to FieldLabel.
    XAML
    Copy Code
    ...
    <Intersoft:UXWindow.Resources>
                    
            <Style x:Key="FieldLabelStyle" TargetType="Intersoft:FieldLabel">
                    <Setter Property="HeaderWidth" Value="160"/>
                    <Setter Property="HorizontalHeaderAlignment" Value="Right"/>
                    <Setter Property="Padding" Value="2"/>
            <Setter Property="HeaderMargin" Value="0,0,8,0"/>
            </Style>
    
    </Intersoft:UXWindow.Resources>
    
    <Intersoft:UXWindow.PrimaryToolBarTemplate>
    ...
  11. Back to the UXItemsControl, Add ID field to the UXItemsControl.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
        <Intersoft:FieldLabel Header="ID:">
            <Intersoft:UXTextBox Width="100" IsReadOnly="True" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
    ...
  12. Create SimpleTextBoxStyle to the UXWindow resources. This is the style that will be assigned to UXTextBox.
    XAML
    Copy Code
    ...
        <Intersoft:UXWindow.Resources>
    
            <Style x:Key="FieldLabelStyle" TargetType="Intersoft:FieldLabel">
                <Setter Property="HeaderWidth" Value="160"/>
                <Setter Property="HorizontalHeaderAlignment" Value="Right"/>
                <Setter Property="Padding" Value="2"/>
                <Setter Property="HeaderMargin" Value="0,0,8,0"/>
            </Style>
    
            <Style x:Key="SimpleTextBoxStyle" TargetType="Intersoft:UXTextBox">
                <Setter Property="HorizontalAlignment" Value="Left"/>
                <Setter Property="Width" Value="200"/>
            </Style>
    
        </Intersoft:UXWindow.Resources>
    ...
  13. Add FullName, Address, State, and ZipCode field by repeating step 10, but remove the IsReadOnly property. For State field, replace the UXTextBox with UXComboBox.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
        <Intersoft:FieldLabel Header="ID:">
            <Intersoft:UXTextBox Width="100" IsReadOnly="True" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Full Name:">
            <Intersoft:UXTextBox Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Address:">
            <Intersoft:UXTextBox Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="State:">
            <Intersoft:UXComboBox DropDownHeight="150" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Zip Code:">
            <Intersoft:UXTextBox Width="100" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
    ...

  14. Add ExpandableGroupBox after the last ExpandableGroupBox. Set Header property to Contact Details, VerticalAlignment to Top and Margin to 0,0,2,0.
    XAML
    Copy Code
    <Intersoft:ExpandableGroupBox Header="Contact Details" VerticalAlignment="Top" Margin="0,0,2,0">
        <Grid Height="150" Width="200" />
    </Intersoft:ExpandableGroupBox>

  15. Clear the content of the ExpandableGroupBox and replace it with UXItemsControl. Set ItemContainerStyle to {StaticResource FieldLabelStyle}. Like step 8.
    XAML
    Copy Code
    ...
    <Intersoft:ExpandableGroupBox Header="Contact Details" VerticalAlignment="Top" Margin="0,0,2,0">
        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
            <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
            </Intersoft:UXItemsControl>
        </Intersoft:UXItemsControl>
    </Intersoft:ExpandableGroupBox>
    ...
  16. Add Mobile, Email and Twitter field inside the UXItemsControls by repeating step 12, but remove the IsReadOnly property.
    XAML
    Copy Code
    ...
    <Intersoft:ExpandableGroupBox Header="Contact Details" VerticalAlignment="Top" Margin="0,0,2,0">
        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
            <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                <Intersoft:FieldLabel Header="Mobile:">
                    <Intersoft:UXTextBox Width="200" />
                </Intersoft:FieldLabel>
                <Intersoft:FieldLabel Header="Email:">
                    <Intersoft:UXTextBox Width="200" />
                </Intersoft:FieldLabel>
                <Intersoft:FieldLabel Header="Twitter:">
                    <Intersoft:UXTextBox Width="200" />
                </Intersoft:FieldLabel>
            </Intersoft:UXItemsControl>
        </Intersoft:UXItemsControl>
    </Intersoft:ExpandableGroupBox>
    ...

Creating the ViewModel

This section steps you through the process of creating a ViewModel class that contains the properties to describe the View that you created in the previous section. The ViewModel defines a DelegateCommand to represent the view command and logic for save action.

To create the Contact ViewModel

  1. Create a new ContactViewModel that inherit from ViewModelBase class by add new class to ViewModels folder and named it ContactViewModel.cs.
    C#
    Copy Code
    ...
    namespace ClientUIMVVMApp2.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; }
            }
        }
    }
    ...

To create the EditClientProfileViewModel

  1. In the ViewModels folder, add new class and named it EditClientProfileViewModel.cs. This new class will inherit ViewModelBase class. This is the class that will become the DataContext's property of View.
    C#
    Copy Code
    namespace ClientUIMVVMApp2.ViewModels
    {
        public class EditClientProfileViewModel : ViewModelBase
        {
    
        }
    }
  2. Start creating the EditClientProfileViewModel class. Here is the complete EditClientProfileViewModel.cs.
    C#
    Copy Code
    public class EditClientProfileViewModel : ViewModelBase
    {
        #region Constructor
    
        public EditClientProfileViewModel()
        {
            this.Contact = new Contact
            {
                Id = "JOSE",
                Name = "José Pedro Freyre",
                Address = "C/ Romero, 33",
                Phone = "1-843-371-8211",
                Cell = "1-555-123-9250",
                Email = "jose@fabrikam.com",
                Fax = "",
                Blog = "http://www.cpandl.com/",
                Twitter = "http://twitter.com/jose",
                Website = "http://www.fabrikam.com/",
                State = StateCode.GA,
                ZipCode = "57998",
                Photo = new Uri("/ClientUIMVVMApp2;component/Assets/Photos/8.jpg", UriKind.RelativeOrAbsolute)
            }; 
            this.StateCodes = new StateCodeDataProvider().Data;
        }
    
        #endregion
    
        #region Fields
    
        private Contact _contact;
    
        #endregion
    
        #region Properties
    
        public IEnumerable StateCodes { get; private set; }
    
        public Contact Contact
        {
            get {return _contact; }
            set
            {
                if (_contact != value)
                {
                    _contact = value;
                    OnPropertyChanged("Contact");
                }
            }
        }
        #endregion
    }
  3. Create DelegateCommand to EditClientProfileViewModel class.
    C#
    Copy Code
    private DelegateCommand _saveCommand = null;
    public EditClientProfileViewModel()
    {
        this.Contact = new Contact
        {
            Id = "JOSE",
            Name = "José Pedro Freyre",
            Address = "C/ Romero, 33",
            Phone = "1-843-371-8211",
            Cell = "1-555-123-9250",
            Email = "jose@fabrikam.com",
            Fax = "",
            Blog = "http://www.cpandl.com/",
            Twitter = "http://twitter.com/jose",
            Website = "http://www.fabrikam.com/",
            State = StateCode.GA,
            ZipCode = "57998",
            Photo = new Uri("/ClientUIMVVMApp2;component/Assets/Photos/8.jpg", UriKind.RelativeOrAbsolute)
        }; 
        this.StateCodes = new StateCodeDataProvider().Data;
        this._saveCommand = new DelegateCommand(ExecuteSave, CanExecuteSave);
    }
  4. Create DelegateCommand SaveCommand property.
    C#
    Copy Code
    public DelegateCommand SaveCommand
    {
        get { return _saveCommand; }
        set
        {
            if (_saveCommand != value)
            {
                _saveCommand = value;
                OnPropertyChanged("SaveCommand");
            }
        }
    }
  5. Create CanExecuteSave method. This is the method that will validate whether or not the Save UXToolBarButton is active or not.
    C#
    Copy Code
    private bool CanExecuteSave(object parameter)
    {
        return true;
    }
  6. Create ExecuteSave method. This is the method that will be triggered if the Save UXToolBarButton is clicked.
    C#
    Copy Code
    private void ExecuteSave(object parameter)
    {
        MessageBoxServiceProvider.Standalone = true;
    
        MessageBoxServiceProvider.Show("Execute Save DelegateCommand", "Information",
            Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK,
            Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information,
            null);
    }
  7. Specify Standalone property to MessageBoxServiceProvider.cs. In this sample, the Standalone property will always set to True so the dependency checking will be ignored.
    C#
    Copy Code
    ...
    public static IWindow Owner
    {
        get
        {
            if (Standalone)
                return null;
    
            FrameworkElement element = ISFocusManager.GetFocusedElement() as FrameworkElement;
            IWindow owner = null;
    
            // check if the caller is hosted within a known container
            // if the dependency container is of IWindow type, use it as the owner of this modal window
            if (element != null)
            {
                DependencyObject logicalContainer = ISFocusManager.GetLogicalContainerScope(element);
    
                if (logicalContainer is IWindow)
                    owner = logicalContainer as IWindow;
            }
    
            return owner;
        }
    }
    
    public static bool Standalone { get; set; }
    ...
  8. Here is the final EditClientProfileViewModel class after implement DelegateCommand.
    C#
    Copy Code
    public class EditClientProfileViewModel : ViewModelBase
    {
        #region Constructor
    
        public EditClientProfileViewModel()
        {
            this.Contact = new Contact
            {
                Id = "JOSE",
                Name = "José Pedro Freyre",
                Address = "C/ Romero, 33",
                Phone = "1-843-371-8211",
                Cell = "1-555-123-9250",
                Email = "jose@fabrikam.com",
                Fax = "",
                Blog = "http://www.cpandl.com/",
                Twitter = "http://twitter.com/jose",
                Website = "http://www.fabrikam.com/",
                State = StateCode.GA,
                ZipCode = "57998",
                Photo = new Uri("/ClientUIMVVMApp2;component/Assets/Photos/8.jpg", UriKind.RelativeOrAbsolute)
            }; 
            this.StateCodes = new StateCodeDataProvider().Data;
            this._saveCommand = new DelegateCommand(ExecuteSave, CanExecuteSave);
        }
    
        #endregion
    
        #region Fields
    
        private Contact _contact;
        private DelegateCommand _saveCommand = null;
    
        #endregion
    
        #region Properties
    
        public IEnumerable StateCodes { get; private set; }
    
        public Contact Contact
        {
            get {return _contact; }
            set
            {
                if (_contact != value)
                {
                    _contact = value;
                    OnPropertyChanged("Contact");
                }
            }
        }
    
        public DelegateCommand SaveCommand
        {
            get { return _saveCommand; }
            set
            {
                if (_saveCommand != value)
                {
                    _saveCommand = value;
                    OnPropertyChanged("SaveCommand");
                }
            }
        }
    
        #endregion
    
        #region Methods
    
        private bool CanExecuteSave(object parameter)
        {
            return true;
        }
    
        private void ExecuteSave(object parameter)
        {
            MessageBoxServiceProvider.Standalone = true;
    
            MessageBoxServiceProvider.Show("Execute Save DelegateCommand", "Information",
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK,
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information,
                null);
        }
    
        #endregion
    }

Binding View to ViewModel

This section show how to bind the ViewModel that was created in the previous section to the View for example you will bind the Source property of Image to Contact.Photo property.
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 section shows how to instantiate the ViewModel in the XAML page and bind the UI elements to the properties in the ViewModel such as the data context, selection and command.

To bind the EditClientProfileView to EditClientProfileViewModel

  1. Open EditClientProfile.xaml. Declare the namespace that maps to the EditClientProfileViewModel class in the EditClientProfile page.
    XAML
    Copy Code
    ..
    <Intersoft:UXWindow 
            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:ViewModels="clr-namespace:ClientUIMVVMApp2.ViewModels"
            mc:Ignorable="d"
    ..      
    <Intersoft:UXWindow.DataContext>
        <ViewModels:EditClientProfileViewModel />
    </Intersoft:UXWindow.DataContext>
    ...
  2. Bind Source property of the Image control. Set the Source to {Binding Contact.Photo}.
    XAML
    Copy Code
    ...
    <Intersoft:ContentReflector HorizontalAlignment="Left" Width="160" 
                            VerticalContentAlignment="Bottom" Margin="12">
        <Image Source="{Binding Contact.Photo}"/>
    </Intersoft:ContentReflector>
    ...


    Note that if you can not see any data appear, please try to rebuild.
  3. Bind all UXTextBox that represent ID, FullName, Address, State and ZipCode fields to the Contact properties, such as shown in the following code.
    XAML
    Copy Code
    ...
    <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
        <Intersoft:FieldLabel Header="ID:">
            <Intersoft:UXTextBox Width="100" Text="{Binding Contact.Id}" IsReadOnly="True" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Full Name:">
            <Intersoft:UXTextBox Text="{Binding Contact.Name, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Address:">
            <Intersoft:UXTextBox Text="{Binding Contact.Address, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="State:">
            <Intersoft:UXComboBox DropDownHeight="150" ItemsSource="{Binding Path=StateCodes}" SelectedItem="{Binding Path=Contact.State, Mode=TwoWay}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Zip Code:">
            <Intersoft:UXTextBox Width="100" Text="{Binding Contact.ZipCode, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
    ...

  4. Bind all the UXTextBox that represent Mobile, Email and Twitter fields to the Contact properties, such as shown in the following example. 
    XAML
    Copy Code
    ...
    <Intersoft:ExpandableGroupBox Header="Contact Details" VerticalAlignment="Top" Margin="0,0,2,0">
        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
            <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                <Intersoft:FieldLabel Header="Mobile:">
                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Cell, Mode=TwoWay}" />
                </Intersoft:FieldLabel>
                <Intersoft:FieldLabel Header="Email:">
                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Email, Mode=TwoWay}" />
                </Intersoft:FieldLabel>
                <Intersoft:FieldLabel Header="Twitter:">
                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Twitter, Mode=TwoWay}" />
                </Intersoft:FieldLabel>
            </Intersoft:UXItemsControl>
        </Intersoft:UXItemsControl>
    </Intersoft:ExpandableGroupBox>
    ...

  5. Bind the UXToolBarButton to SaveCommand in EditClientProfile.xaml such as shown in the following example.

    XAML
    Copy Code
    ...
    <Intersoft:UXToolGroup>
        <Intersoft:UXToolBarButton Content="Save" DisplayMode="ContentAndImage"
                                    Icon="/Intersoft.ClientUI.Samples.Assets;component/Images/Office/SaveHS.png"
                                    ToolTipService.ToolTip="Save Changes"
                                    Command="{Binding SaveCommand}"/>
        <Intersoft:UXSeparator/>
        <Intersoft:UXToolBarButton Content="Cancel"  DisplayMode="ContentAndImage"
                                    Icon="/Intersoft.ClientUI.Samples.Assets;component/Images/Commands/Cancel.png"
                                    ToolTipService.ToolTip="Cancel Changes (Not implemented in this sample)"/>
    </Intersoft:UXToolGroup>
    ...
  6. Since EditClientProfile.xaml is a window, then there should be a page that have or refers to EditClientProfile.xaml. Double click on MainPage.xml and add EditClientProfile window into it.
    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:window="clr-namespace:ClientUIMVVMApp2.Views"
            mc:Ignorable="d"
            xmlns:Intersoft="http://intersoft.clientui.com/schemas"
            x:Class="ClientUIMVVMApp2.MainPage" 
            Title="MainPage Page"
            d:DesignWidth="640" d:DesignHeight="480">
            
            <Grid x:Name="LayoutRoot">
            <window:EditClientProfile IsClientVisible="True" IsActive="True" VerticalAlignment="Center" Width="600" Height="400"/>
        </Grid>
    </Intersoft:UXPage>
    ...

    Make sure that in App.xaml.cs, the Application StartUp should be set to MainPage.
    C#
    Copy Code
    ...
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        this.RootVisual = new MainPage();
    }
    ...
  7. Save, build and run the project.
  8. The following screenshot describe when Save button is clicked.

In this walkthrough, you have learned how to create ClientUI MVVM project using project template, and create the classes and page based on the Model, View and ViewModel pattern. You also learned how to bind the UXToolBarButton to a DelegateCommand in the ViewModel which performs save action.

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 Constructor

        private Contact(string id, string name, string email, string phone, string twitter, string website, Uri photo)
        {
            this._id = id;
            this._name = name;
            this._email = email;
            this._phone = phone;
            this._twitter = twitter;
            this._website = website;
            this._photo = photo;
        }

        public Contact()
            : this(id: string.Empty, name: string.Empty, email: string.Empty, phone: string.Empty, twitter: string.Empty, website: string.Empty, photo: null)
        {
        }

        #endregion

        #region Fields

        private string _id;
        private string _name;
        private string _email;
        private string _phone;
        private string _twitter;
        private string _website;
        private Uri _photo;

        #endregion

        #region Properties

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

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

        public string Email
        {
            get { return this._email; }
            set
            {
                if (this._email != value)
                {
                    this._email = value;
                    this.ClearError("Email");
                    this.OnPropertyChanged("Email");
                }
            }
        }

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

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

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

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

        #endregion

        #region Methods
        
        public void SetPhoto(string uri)
        {
            this.Photo = new Uri("/MVVMApplicationWalkthrough;component/Assets/Photos/" + uri + ".jpg", UriKind.RelativeOrAbsolute);
        }
        #endregion
    }

}

State.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;

namespace ClientUIMVVMApp2.Models
{
    public enum StateCode
    {
        AL, // Alabama
        AK, // Alaska
        AS, // American Samoa
        AZ, // Arizona
        AR, // Arkansas
        CA, // California
        CO, // Colorado
        CT,
        DE,
        DC,
        FL,
        GA,
        GU,
        HI,
        ID,
        IL,
        IN,
        IA,
        KS,
        KY,
        LA,
        ME,
        MD,
        MH,
        MA,
        MI,
        FM,
        MN,
        MS,
        MO,
        MT,
        NE,
        NV,
        NH,
        NJ,
        NM,
        NY,
        NC,
        ND,
        MP,
        OH,
        OK,
        OR,
        PW,
        PA,
        PR,
        RI,
        SC,
        SD,
        TN,
        TX,
        UT,
        VT,
        VA,
        VI,
        WA,
        WV,
        WI,
        WY,
    }
}

EnumDataProvider.cs

C#
Copy Code
using System;
using System.Collections;
using System.Collections.Generic;
using ClientUIMVVMApp2.Models;

namespace ClientUIMVVMApp2.Converter
{
    public abstract class EnumDataProvider<T>
    {
        IEnumerable _data;

        public IEnumerable Data
        {
            get
            {
                if (this._data == null)
                {
                    Type enumType = typeof(T);
                    List<object> list = new List<object>();
                    int value = 0;

                    while (Enum.IsDefined(enumType, value))
                    {
                        list.Add(Enum.ToObject(enumType, value));
                        value++;
                    }

                    this._data = list;
                }

                return this._data;

            }
        }
    }

    public sealed class StateCodeDataProvider : EnumDataProvider<StateCode>
    {
    }
}

EditClientProfile.xaml

XAML
Copy Code
<Intersoft:UXWindow 
        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:ViewModels="clr-namespace:ClientUIMVVMApp2.ViewModels"
        mc:Ignorable="d"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
        x:Class="ClientUIMVVMApp2.Views.EditClientProfile" 
        Header="EditClientProfile"
        d:DesignWidth="640" d:DesignHeight="480">

    <Intersoft:UXWindow.DataContext>
        <ViewModels:EditClientProfileViewModel />
    </Intersoft:UXWindow.DataContext>
    
    <Intersoft:UXWindow.Resources>

        <Style x:Key="FieldLabelStyle" TargetType="Intersoft:FieldLabel">
            <Setter Property="HeaderWidth" Value="160"/>
            <Setter Property="HorizontalHeaderAlignment" Value="Right"/>
            <Setter Property="Padding" Value="2"/>
            <Setter Property="HeaderMargin" Value="0,0,8,0"/>
        </Style>

        <Style x:Key="SimpleTextBoxStyle" TargetType="Intersoft:UXTextBox">
            <Setter Property="HorizontalAlignment" Value="Left"/>
            <Setter Property="Width" Value="200"/>
        </Style>

    </Intersoft:UXWindow.Resources>
    
    <Intersoft:UXWindow.PrimaryToolBarTemplate>
        <DataTemplate>
            <Grid>
                <Intersoft:UXToolBar Intersoft:DockPanel.Dock="Top" OverflowHandleVisibility="AsNeeded" Margin="0,8,0,0"
                                                                 GripHandleVisibility="Collapsed" HorizontalAlignment="Left">
                    <Intersoft:UXToolBar.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#90FFFFFF" Offset="0"/>
                            <GradientStop Color="#00B1D0E3" Offset="1"/>
                        </LinearGradientBrush>
                    </Intersoft:UXToolBar.Background>
                    <Intersoft:UXToolGroup>
                        <Intersoft:UXToolBarButton Content="Save" DisplayMode="Content" ToolTipService.ToolTip="Save Changes" Command="{Binding SaveCommand}"/>
                        <Intersoft:UXSeparator/>
                        <Intersoft:UXToolBarButton Content="Cancel"  DisplayMode="Content" ToolTipService.ToolTip="Cancel Changes (Not implemented in this sample)"/>
                    </Intersoft:UXToolGroup>
                </Intersoft:UXToolBar>
            </Grid>
        </DataTemplate>
    </Intersoft:UXWindow.PrimaryToolBarTemplate>
    
    <Grid x:Name="LayoutRoot">
        <Grid>
            <Intersoft:DockPanel FillChildMode="Custom">
                <Intersoft:ContentReflector Name="contentReflector1" Width="160" HorizontalAlignment="Left" VerticalContentAlignment="Bottom" Margin="12">
                    <Image Source="{Binding Contact.Photo}"/>
                </Intersoft:ContentReflector>
                <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
                    <Intersoft:ExpandableGroupBox Header="General Information" VerticalAlignment="Top" Name="expandableGroupBox1">
                        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                            <Intersoft:FieldLabel Header="ID:">
                                <Intersoft:UXTextBox Width="100" Text="{Binding Contact.Id}" IsReadOnly="True" Style="{StaticResource SimpleTextBoxStyle}" />
                            </Intersoft:FieldLabel>
                            <Intersoft:FieldLabel Header="Full Name:">
                                <Intersoft:UXTextBox Text="{Binding Contact.Name, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
                            </Intersoft:FieldLabel>
                            <Intersoft:FieldLabel Header="Address:">
                                <Intersoft:UXTextBox Text="{Binding Contact.Address, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
                            </Intersoft:FieldLabel>
                            <Intersoft:FieldLabel Header="State:">
                                <Intersoft:UXComboBox DropDownHeight="150" ItemsSource="{Binding Path=StateCodes}" SelectedItem="{Binding Path=Contact.State, Mode=TwoWay}" />
                            </Intersoft:FieldLabel>
                            <Intersoft:FieldLabel Header="Zip Code:">
                                <Intersoft:UXTextBox Width="100" Text="{Binding Contact.ZipCode, Mode=TwoWay}" Style="{StaticResource SimpleTextBoxStyle}" />
                            </Intersoft:FieldLabel>
                        </Intersoft:UXItemsControl>
                    </Intersoft:ExpandableGroupBox>
                    <Intersoft:ExpandableGroupBox Header="Contact Details" VerticalAlignment="Top" Margin="0,0,2,0">
                        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                            <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                                <Intersoft:FieldLabel Header="Mobile:">
                                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Cell, Mode=TwoWay}" />
                                </Intersoft:FieldLabel>
                                <Intersoft:FieldLabel Header="Email:">
                                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Email, Mode=TwoWay}" />
                                </Intersoft:FieldLabel>
                                <Intersoft:FieldLabel Header="Twitter:">
                                    <Intersoft:UXTextBox Width="200" Text="{Binding Contact.Twitter, Mode=TwoWay}" />
                                </Intersoft:FieldLabel>
                            </Intersoft:UXItemsControl>
                        </Intersoft:UXItemsControl>
                    </Intersoft:ExpandableGroupBox>
                </StackPanel>
            </Intersoft:DockPanel>
        </Grid>
    </Grid>
</Intersoft:UXWindow>

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 ClientUIMVVMApp2.Models;

namespace ClientUIMVVMApp2.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; }
        }
    }
}

EditClientProfileViewModel.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 ClientUIMVVMApp2.Converter;
using ClientUIMVVMApp2.Models;
using System.Collections;
using Intersoft.Client.Framework.Input;

namespace ClientUIMVVMApp2.ViewModels
{
    public class EditClientProfileViewModel : ViewModelBase
    {
        #region Constructor

        public EditClientProfileViewModel()
        {
            this.Contact = new Contact
            {
                Id = "JOSE",
                Name = "José Pedro Freyre",
                Address = "C/ Romero, 33",
                Phone = "1-843-371-8211",
                Cell = "1-555-123-9250",
                Email = "jose@fabrikam.com",
                Fax = "",
                Blog = "http://www.cpandl.com/",
                Twitter = "http://twitter.com/jose",
                Website = "http://www.fabrikam.com/",
                State = StateCode.GA,
                ZipCode = "57998",
                Photo = new Uri("/ClientUIMVVMApp2;component/Assets/Photos/8.jpg", UriKind.RelativeOrAbsolute)
            }; 
            this.StateCodes = new StateCodeDataProvider().Data;
            this._saveCommand = new DelegateCommand(ExecuteSave, CanExecuteSave);
        }

        #endregion

        #region Fields

        private Contact _contact;
        private DelegateCommand _saveCommand = null;

        #endregion

        #region Properties

        public IEnumerable StateCodes { get; private set; }

        public Contact Contact
        {
            get {return _contact; }
            set
            {
                if (_contact != value)
                {
                    _contact = value;
                    OnPropertyChanged("Contact");
                }
            }
        }

        public DelegateCommand SaveCommand
        {
            get { return _saveCommand; }
            set
            {
                if (_saveCommand != value)
                {
                    _saveCommand = value;
                    OnPropertyChanged("SaveCommand");
                }
            }
        }

        #endregion

        #region Methods

        private bool CanExecuteSave(object parameter)
        {
            return true;
        }

        private void ExecuteSave(object parameter)
        {
            MessageBoxServiceProvider.Standalone = true;

            MessageBoxServiceProvider.Show("Execute Save DelegateCommand", "Information",
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK,
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information,
                null);
        }

        #endregion
    }
}
See Also

Concepts

Other Resources