Intersoft ClientUI Documentation
Walkthrough: Create Linked Input on Two UXComboBox using MVVM Pattern

This walkthrough shows you how to use MVVM pattern to create a linked UXComboBox and show detailed info for the selected item. This walkthrough demonstrates the following concept:

Prerequisites

You need the following components to complete this walkthrough:

Creating a New Intersoft 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\FontDataSource.xml.
  3. Click on the FontDataSource.xml file and press F4 to open the Property Window. Change the Build Action property to Resources

Creating the Model class 

This section shows how to create a Model class in Font.cs and FontWeight.cs. The model will map each information in the data entity to a property.

To create the FontWeight model

  1. Create a new FontWeight.cs under the Models folder and inherit the ModelBase class.
  2. Create a private variable and a public property for Name node with a String data type. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
  3. Repeat the same step for Price node.
    C#
    Copy Code
    private string _name;
    private string _price;
    
    public string Name
    {
        get { return _name; }
        set 
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    
    public string Price
    {
        get { return _price; }
        set
        {
            if (_price != value)
            {
                _price = value;
                OnPropertyChanged("Price");
            }
        }
    }

To create the Font model

  1. Create a new Font.cs under the Models folder and inherit the ModelBase class.
  2. Create a private variable and a public property for Name node with a String data type. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
  3. Repeat the same step for FontWeights node using collection of FontWeight model as the data type.
    C#
    Copy Code
    private string _name;
    private ObservableCollection<FontWeight> _fontWeights;
    
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    
    public ObservableCollection<FontWeight> FontWeights
    {
        get { return _fontWeights; }
        set
        {
            if (_fontWeights != value)
            {
                _fontWeights = value;
                OnPropertyChanged("FontWeights");
            }
        }
    }
  4. Create a constructor which accept XElement parameter. The constructor maps information in the data entity to each property in the class.
    C#
    Copy Code
    public Font(XElement h)
    {
        Name = h.Element("Name").Value.ToString();
        FontWeights = new ObservableCollection<FontWeight>();
    
        foreach (XElement fontWeight in h.Descendants("FontWeight"))
        {
            FontWeights.Add(new FontWeight() { 
                Name = fontWeight.Element("Name").Value.ToString(),
                Price = fontWeight.Element("Price").Value.ToString()
            });
        }
    }

Creating the View

This section shows how to create a View pattern used in the application interface using LinkCombo.xaml. We bind the data to the control in later section

To create the LinkCombo view

  1. Add a new UXPage to the Views folder in your Silverlight project and name it LinkCombo.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
  2. Add a UXStackPanel.
  3. Add two FieldLabel control and a TextBlock control to the page.
  4. Set the Header property to Select Font: in the first FieldLabel. On the second FieldLabel set it to Select FontWeight:.
  5. Set the following properties in the UXStackPanel.
    Property Value
    Width Auto
    Height Auto
    Orientation Vertical
  6. Set FieldLabel Content property to use UXComboBox. The project will automatically reference Intersoft.Client.UI.Aqua.UXCollection if the control is added using toolbox.

Creating the ViewModel

This section shows how to create a ViewModel to hold the collection of Font and FontWeight model object. There is also properties to hold the UXComboBox SelectedItem and selection summary.

To create the LinkComboViewModel ViewModel

  1. Create a new LinkComboViewModel.cs under the ViewModels folder and inherit the ViewModelBase class.
  2. Create a private variable and a public property to hold collection of Font object. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
    C#
    Copy Code
    private ObservableCollection<Font> _fonts;
    
    public ObservableCollection<Font> Fonts
    {
        get { return _fonts; }
        set
        {
            if (_fonts != value)
            {
                _fonts = value;
                OnPropertyChanged("Fonts");
            }
        }
    }
  3. Repeat the same step for collection of FontWeight object.
  4. Create a private variable and a public property to hold the selected Font object. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
    C#
    Copy Code
    private Font _selectedFont;
    
    public Font SelectedFont
    {
        get { return _selectedFont; }
        set
        {
            if (_selectedFont != value)
            {
                _selectedFont = value;
                OnPropertyChanged("SelectedFont");
            }
        }
    }
  5. Repeat the same step for selected FontWeight object.
  6. Create a private variable and a public property to hold the selected Models summary. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
    C#
    Copy Code
    private string _priceInfo;
    
    public string PriceInfo
    {
        get { return _priceInfo; }
        set
        {
            if (_priceInfo != value)
            {
                _priceInfo = value;
                OnPropertyChanged("PriceInfo");
            }
        }
    }
  7. Create a LoadData method to fill the Fonts collection based on the data from FontDataSource.xml. This method is called during object construction.
    C#
    Copy Code
    public LinkComboViewModel()
    {
        LoadData();
    }
    
    public void LoadData()
    {
        StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
            new Uri("LinkUXComboBoxMVVM;component/Data/FontDataSource.xml",UriKind.Relative));
    
        XDocument doc = XDocument.Load(resource.Stream);
    
        Fonts = new ObservableCollection<Font>();
    
        foreach(XElement font in doc.Descendants("Font"))
        {
            Fonts.Add(new Font(font));
        }
    
        resource.Stream.Close();
    }
  8. Modify the SelectedFont property to set the FontWeights collection based on the SelectedFont and reset the PriceInfo property.
    C#
    Copy Code
    public Font SelectedFont
    {
        get { return _selectedFont; }
        set
        {
            if (_selectedFont != value)
            {
                _selectedFont = value;
    
                if (_selectedFont != null)
                    FontWeights = _selectedFont.FontWeights;
                PriceInfo = "";
    
                OnPropertyChanged("SelectedFont");
            }
        }
    }
  9. Modify the SelectedFontWeight property to set the PriceInfo based on the SelectedFont Name, SelectedtFontWeight Name and Price detail.
    C#
    Copy Code
    public FontWeight SelectedFontWeight
    {
        get { return _selectedFontWeight; }
        set
        {
            if (_selectedFontWeight != value)
            {
                _selectedFontWeight = value;
    
                PriceInfo = string.Format("{0} {1} {2}", SelectedFont.Name,
                    _selectedFontWeight.Name, _selectedFontWeight.Price);
    
                OnPropertyChanged("SelectedFontWeight");
            }
        }
    }

Binding the ViewModel to View

This section shows how to bind the ViewModel property object to the LinkCombo page.

To bind the LinkComboViewModel ViewModel

  1. Declare the namespace that maps to the LinkComboViewModel class.
    XAML
    Copy Code
    <Intersoft:UXPage 
            ...
        xmlns:ViewModels="clr-namespace:LinkUXComboBoxMVVM.ViewModels"
            ...
        >
        ...
    </Intersoft:UXPage>
  2. Reference the LinkComboViewModel as the page DataContext.
    XAML
    Copy Code
    <Intersoft:UXPage.DataContext>
        <ViewModels:LinkComboViewModel />
    </Intersoft:UXPage.DataContext>
  3. In the first UXComboBox properties window.
    Locate the ItemsSource property.
    1. Click the ellipsis button in the header property column, a context menu will appear
    2. Select the Apply DataBinding Options...
    3. From the Tab Path, select Fonts
    Locate the SelectedItem property.
    1. Click the ellipsis button in the header property column, a context menu will appear
    2. Select the Apply DataBinding Options...
    3. From the Tab Path, select SelectedFont
    4. From the Tab Options, set Mode to TwoWay
    Locate the DisplayMemberPath property and set the value to Name.
    XAML
    Copy Code
    <Intersoft:UXComboBox Name="uXComboBox1" Width="175" ItemsSource="{Binding Path=Fonts}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedFont, Mode=TwoWay}" />
  4. In the second UXComboBox properties window.
    Locate the ItemsSource property.
    1. Click the ellipsis button in the header property column, a context menu will appear
    2. Select the Apply DataBinding Options...
    3. From the Tab Path, select FontWeights
    Locate the SelectedItem property.
    1. Click the ellipsis button in the header property column, a context menu will appear
    2. Select the Apply DataBinding Options...
    3. From the Tab Path, select SelectedFontWeight
    4. From the Tab Options, set Mode to TwoWay
    Locate the DisplayMemberPath property and set the value to Name.
    XAML
    Copy Code
    <Intersoft:UXComboBox Name="uXComboBox2" Width="175" SelectedItem="{Binding Path=SelectedFontWeight, Mode=TwoWay}" DisplayMemberPath="Name" ItemsSource="{Binding Path=FontWeights}" />
            
  5. In the TextBlock properties window.
    Locate the Text property.
    1. Click the ellipsis button in the header property column, a context menu will appear
    2. Select the Apply DataBinding Options...
    3. From the Tab Path, select PriceInfo

Viewing the Result

In order to view the result, you will need to build the Silverlight project and run the test page in browser.

To view the result

  1. FontWeight UXComboBox will only show collection of FontWeight based on the Font selection.
  2. The TextBlock control will show the summary of the selected item.

Conclusion

In this walkthrough, you have learned how to create ClientUI MVVM Application project using Intersoft ClientUI MVVM Application project template, and create classes with page based on the MVVM pattern. You also learned how to linked two UXComboBox.

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.

FontWeight.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 LinkUXComboBoxMVVM.ViewModels;

namespace LinkUXComboBoxMVVM.Models
{
    public class FontWeight: ModelBase
    {
        private string _name;
        private string _price;

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

        public string Price
        {
            get { return _price; }
            set
            {
                if (_price != value)
                {
                    _price = value;
                    OnPropertyChanged("Price");
                }
            }
        }

        public FontWeight()
        {

        }
    }
}

Font.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 LinkUXComboBoxMVVM.ViewModels;
using System.Xml.Linq;
using System.Collections.ObjectModel;

namespace LinkUXComboBoxMVVM.Models
{
    public class Font: ModelBase
    {
        private string _name;
        private ObservableCollection<FontWeight> _fontWeights;

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

        public ObservableCollection<FontWeight> FontWeights
        {
            get { return _fontWeights; }
            set
            {
                if (_fontWeights != value)
                {
                    _fontWeights = value;
                    OnPropertyChanged("FontWeights");
                }
            }
        }

        public Font(XElement h)
        {
            Name = h.Element("Name").Value.ToString();
            FontWeights = new ObservableCollection<FontWeight>();

            foreach (XElement fontWeight in h.Descendants("FontWeight"))
            {
                FontWeights.Add(new FontWeight() { 
                    Name = fontWeight.Element("Name").Value.ToString(),
                    Price = fontWeight.Element("Price").Value.ToString()
                });
            }
        }
    }
}

LinkComboViewModel.cs

C#
Copy Code
using System;
using System.Net;
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 LinkUXComboBoxMVVM.Models;
using System.Windows.Resources;
using System.Xml.Linq;

namespace LinkUXComboBoxMVVM.ViewModels
{
    public class LinkComboViewModel : ViewModelBase
    {
        private ObservableCollection<Font> _fonts;
        private ObservableCollection<FontWeight> _fontWeights;
        private Font _selectedFont;
        private FontWeight _selectedFontWeight;
        private string _priceInfo;

        public ObservableCollection<Font> Fonts
        {
            get { return _fonts; }
            set
            {
                if (_fonts != value)
                {
                    _fonts = value;
                    OnPropertyChanged("Fonts");
                }
            }
        }

        public ObservableCollection<FontWeight> FontWeights
        {
            get { return _fontWeights; }
            set
            {
                if (_fontWeights != value)
                {
                    _fontWeights = value;
                    OnPropertyChanged("FontWeights");
                }
            }
        }

        public Font SelectedFont
        {
            get { return _selectedFont; }
            set
            {
                if (_selectedFont != value)
                {
                    _selectedFont = value;

                    if (_selectedFont != null)
                        FontWeights = _selectedFont.FontWeights;
                    PriceInfo = "";

                    OnPropertyChanged("SelectedFont");
                }
            }
        }

        public FontWeight SelectedFontWeight
        {
            get { return _selectedFontWeight; }
            set
            {
                if (_selectedFontWeight != value)
                {
                    _selectedFontWeight = value;

                    PriceInfo = string.Format("{0} {1} {2}", SelectedFont.Name,
                        _selectedFontWeight.Name, _selectedFontWeight.Price);

                    OnPropertyChanged("SelectedFontWeight");
                }
            }
        }

        public string PriceInfo
        {
            get { return _priceInfo; }
            set
            {
                if (_priceInfo != value)
                {
                    _priceInfo = value;
                    OnPropertyChanged("PriceInfo");
                }
            }
        }

        // Constructors
        public LinkComboViewModel()
        {
            LoadData();
        }

        public void LoadData()
        {
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
                new Uri("LinkUXComboBoxMVVM;component/Data/FontDataSource.xml",UriKind.Relative));

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

            Fonts = new ObservableCollection<Font>();

            foreach(XElement font in doc.Descendants("Font"))
            {
                Fonts.Add(new Font(font));
            }

            resource.Stream.Close();
        }
    }
}

LinkCombo.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:LinkUXComboBoxMVVM.ViewModels"
        mc:Ignorable="d"
        x:Class="LinkUXComboBoxMVVM.Views.LinkCombo" 
        Title="LinkCombo Page"
        d:DesignWidth="640" d:DesignHeight="480">
        
    <Intersoft:UXPage.DataContext>
        <ViewModels:LinkComboViewModel />
    </Intersoft:UXPage.DataContext>
    
        <Grid x:Name="LayoutRoot">
        <Intersoft:UXStackPanel HorizontalAlignment="Left" Margin="10,10,0,0" Name="uXStackPanel1" VerticalAlignment="Top" Orientation="Vertical">
            <Intersoft:FieldLabel Header="Select Font: " Name="fieldLabel1" HeaderWidth="125">
                <Intersoft:UXComboBox Name="uXComboBox1" Width="175" ItemsSource="{Binding Path=Fonts}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedFont, Mode=TwoWay}" />
            </Intersoft:FieldLabel>
            <Intersoft:FieldLabel Header="Select FontWeight: " Name="fieldLabel2" HeaderWidth="125">
                <Intersoft:UXComboBox Name="uXComboBox2" Width="175" SelectedItem="{Binding Path=SelectedFontWeight, Mode=TwoWay}" DisplayMemberPath="Name" ItemsSource="{Binding Path=FontWeights}" />
            </Intersoft:FieldLabel>
            <TextBlock Height="23" Name="textBlock1" Text="{Binding Path=PriceInfo}" />
        </Intersoft:UXStackPanel>
    </Grid>
</Intersoft:UXPage>
See Also

Concepts

Other Resources