Intersoft ClientUI Documentation
Walkthrough: Displaying Item Detail using Rich User Interface Controls with MVVM Pattern

This walkthrough shows you how to displaying item detail using rich user interface controls with 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 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 SampleData.
  2. In SampleDatafolder, insert the data source from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI Samples\Intersoft.ClientUI.Samples.Assets\Data\HotelDataSource..xml.
  3. Click on the HotelDataSource.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 Images.
  2. In Images folder, create new folder with name Hotels.
  3. In Hotels folder, copy the images from[Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI Samples\Intersoft.ClientUI.Samples.Assets\Images\Hotels.

Creating Model Class

This section shows how to create the Hotel model class that represents the data entity used in this walkthrough. The Hotel model class contains constructors to easily parse data from XML.

To Create the Hotel Model Class

  1. Create a model class that inherits ModelBase class under the Models folder. You can name it Hotel.cs.
  2. Add Name property to the Hotel model class. 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 _name;
    
    public string Name
    {
        get { return this._name; }
        set {
            if (this._name != value) {
                this._name = value;
                OnPropertyChanged("Name");
            }
        }
    }
  3. Also add Location, Rating, Rate and Image property to the Hotel model class by repeating step number 2.
    C#
    Copy Code
    private string _name;
    private string _location;
    private string _rating;
    private string _rate;
    private string _image;
    
    public string Name
    {
        get { return this._name; }
        set {
            if (this._name != value) {
                this._name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    
    public string Location
    {
        get { return this._location; }
        set {
            if (this._location != value) {
                this._location = value;
                OnPropertyChanged("Location");
            }
        }
    }
    
    public string Rating
    {
        get { return this._rating; }
        set {
            if (this._rating != value) {
                this._rating = value;
                OnPropertyChanged("Rating");
            }
        }
    }
            
    public string Rate
    {
        get { return this._rate; }
        set
        {
            if (this._rate != value)
            {
                this._rate = value;
                OnPropertyChanged("Rate");
            }
        }
    }
    
    public string Image
    {
        get { return this._image; }
        set
        {
            if (this._image != value)
            {
                this._image = value;
                OnPropertyChanged("Image");
            }
        }
    }
  4. Add contstructor that accept XElement parameter to parse the data from XElement.
    C#
    Copy Code
        using System.Xml.Linq;
    
        public class Hotel : ModelBase
        {
            ...
            public Hotel(XElement x)
            {
                this._name = x.Element("Name").Value.Trim();
                this._location = x.Element("Location").Value.Trim();
                this._rating = x.Element("Rating").Value.Trim();
                this._rate = x.Element("Rate").Value.Trim();
                this._image = x.Element("Image").Value.Trim();
            }
        }

Creating The View

This section steps you through the process of creating a page that uses a variety of ClientUI controls such as UXListBox, CallOut, UXScroller and GlassLabel. The UXListBox is used to display a collection of hotel data and when selected it will change CallOut data context to display selected hotel data.

To create the View

  1. Add a new UXPage to the Views folder in your Silverlight project and name it HotelPage.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. Open the newly created HotelPage.xaml page and clear the content inside the LayoutRoot.
  3. Set the Background property to x:Null, the Width property to 640 and the Height property to 480 for LayoutRoot.
  4. Add Border control to the Grid and set the CornerRadius property to 20.
  5. Add the Background color into Border using LinearGradientBrush.
  6. Insert two GradientStop With Color property set to Gray and Offset property set to 0.5. The other GradientStop Color property set to LightGray and Offset property set to 1.
  7. Add DropShadowEffect effect to the Border and set the Color property to Gray.
  8. Add DockPanel to the Border and set the FillChildMode property to Custom.
  9. Add GlassLabel control to the DockPanel and set the Content property to Hotel, Intersoft:DockPanel.Dock property to Top and SpreadBackground property to Gray.
  10. Add UXScroller control after GlassLabel control and set the Intersoft:DockPanel.Dock property to Left and the Margin property to 10 10 0 10.
  11. Add UXListBox control to the UXScroller control and set the Background property to Black and set Name property to HotelList.
  12. Add CallOut control after UXScroller control and set the following properties to the control. 
    Property Value
    Name HotelCallOut
    Visibility Visible
    Intersoft:DockPanel.IsFillElement True
    StrokeThickness 0
    CornerRadius 10
    PointerPosition Left
    PointerPoint1 12, 0
    PointerPoint2 0,20
    PointerPoint3 -12, 0
    Margin 0 20 20 20
  13. Add Background inside CallOut using ImageBrush and set the Stretch property to UniformToFill.
    XAML
    Copy Code
    <Grid x:Name="LayoutRoot" Background="{x:Null}" Width="640" Height="480" DataContext="{StaticResource vwHotel}">        <Border CornerRadius="20">            <Border.Background>                <LinearGradientBrush>                    <GradientStopCollection>                        <GradientStop Color="Gray" Offset="0.5" />                        <GradientStop Color="LightGray" Offset="1" />                    </GradientStopCollection>                </LinearGradientBrush>            </Border.Background>            <Border.Effect>                <DropShadowEffect Color="Gray" />            </Border.Effect>            <Intersoft:DockPanel FillChildMode="Custom">                <Intersoft:GlassLabel Content="Hotel" Intersoft:DockPanel.Dock="Top" SpreadBackground="Gray" />                <Intersoft:UXScroller Intersoft:DockPanel.Dock="Left" Margin="10 10 0 10">                    <Intersoft:UXListBox Name="HotelList" Background="Black" />                </Intersoft:UXScroller>                <Intersoft:CallOut Name="HotelCallOut" Visibility="Visible" Intersoft:DockPanel.IsFillElement="True" StrokeThickness="0" CornerRadius="10" Grid.Column="1" PointerPosition="Left" PointerPoint1="12, 0" PointerPoint2="0,20" PointerPoint3="-12, 0" Margin="0 20 20 20">                    <Intersoft:CallOut.Background>                        <ImageBrush Stretch="UniformToFill" />                    </Intersoft:CallOut.Background>                                    </Intersoft:CallOut>            </Intersoft:DockPanel>        </Border> </Grid>

  14. Add Border after Background and set the VerticalAlignment property to Bottom.
    XAML
    Copy Code
    <Intersoft:CallOut... >
        <Intersoft:CallOut.Background>
            ...
        </Intersoft:CallOut.Background>
        <Border VerticalAlignment="Bottom">
        </Border>
    </Intersoft:CallOut>
  15. Add StackPanel to the Border and set the VerticalAlignment property to Center and the Margin property to 40, 0, 0, 0.
    XAML
    Copy Code
    <Border... >
        <StackPanel VerticalAlignment="Center" Margin="40,0,0,0">
        </StackPanel>
    </Border>
  16. Add TextBlock control to the StackPanel and set the Foreground property to White and the FontSize property to 26.667.
    XAML
    Copy Code
    <Border... >
        <StackPanel... >
            <TextBlock Foreground="White" FontSize="26.667"/>
        </StackPanel>
    </Border>
  17. Add one more TextBlock control to the StackPanel and repeat step 16.
    XAML
    Copy Code
    <Border... >
        <StackPanel... >
            <TextBlock Foreground="White" FontSize="26.667"/>
            <TextBlock Foreground="White" FontSize="18.667"/>
        </StackPanel>
    </Border>

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 the HotelCollection to represent an observable collection of HotelItemViewModel class.

To create the HotelItemViewModel

  1. Add a new class to the ViewModels folder in your Silverlight project and name it HotelItemViewModel.
  2. Open HotelItemViewModel.cs and inherit the class from ViewModelBase class. 
    C#
    Copy Code
    public class HotelItemViewModel : ViewModelBase {  }
  3. Create an constructor and add the Hotel and Id property, such as shown in the following example.
    C#
    Copy Code
    private Hotel _hotel;
    private string _id;
     public HotelItemViewModel(Hotel hotel){    this._hotel = hotel;}
    public string Id
    {
        get { return this._id; }
        set {
            if (this._id != value) {
                this._id = value;
                OnPropertyChanged("Id");
            }
        }
    }
    
    public Hotel Hotel
    {
        get { return this._hotel; }
        set {
            if (this._hotel != null) {
                this._hotel = value;
                OnPropertyChanged("Hotel");
            }
        }
    }

To create the HotelPageViewModel

  1. Add a new class to the ViewModels folder in your Silverlight project and name it HotelPageViewModel.
  2. Open HotelPageViewModel.cs and inherit the class from ViewModelBase class.
    C#
    Copy Code
    public class HotelPageViewModel : ViewModelBase { }
  3. In this view mode, you add the HotelCollection properties which represent a collection of HotelItemViewModel class and SelectedItem properties which represent a HotelItemViewModel, such as shown in the following code listing.
    C#
    Copy Code
    private ObservableCollection<HotelItemViewModel> _hotelCollection;
    private HotelItemViewModel _selectedItem;
    
    public ObservableCollection<HotelItemViewModel> HotelCollection
    {
        get { return this._hotelCollection; }
        set
        {
            if (this._hotelCollection != value) {
                this._hotelCollection = value;
                OnPropertyChanged("HotelCollection");                
            }
        }
    }
    
    public HotelItemViewModel SelectedItem
    {
        get { return this._selectedItem; }
        set {
            if (this._selectedItem != value) {
                this._selectedItem = value;
                OnPropertyChanged("SelectedItem");
            }
        }
    }
  4. Add using System.Linq to using Select method.
  5. Create a LoadHotel method to fill the hotel collection based on the data from HotelDataSource.xml file.
    C#
    Copy Code
    public void LoadHotel()
    {
        StreamResourceInfo stream = System.Windows.Application.GetResourceStream(new Uri("/DisItemDtailUsingRichUICtrlWithMVVMPat;component/SampleData/HotelDataSource.xml", UriKind.Relative));
        XDocument doc = XDocument.Load(stream.Stream);
        var hotels = doc.Descendants("Hotel").Select(a => new Hotel(a));
        _hotelCollection = new ObservableCollection<HotelItemViewModel>();
        int i = 0;
        foreach (var dt in hotels)
        {
            dt.Image = "/DisItemDtailUsingRichUICtrlWithMVVMPat;component/Images/Hotels/" + dt.Image;
            HotelItemViewModel newData = new HotelItemViewModel(dt);
            newData.Id = i.ToString();
            HotelCollection.Add(newData);
            i++;
        }
        stream.Stream.Close();
    }
  6. Add a constructor in HotelPageViewModel and call the method during object construction.
    C#
    Copy Code
    public HotelPageViewModel()
    {
        this.LoadHotel();
    }

Binding the View to the 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 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 and selection.

To bind the HotelPage to the HotelPageViewModel class

  1. Declare the namespace that maps to the HotelPageViewModel class in the HotelPage page.
    XAML
    Copy Code
    <Intersoft:UXPage... 
        xmlns:ViewModels="clr-namespace:DisItemDtailUsingRichUICtrlWithMVVMPat.ViewModels">
    </Intersoft:UXPage>
  2. Instantiate a new instance of the HotelPageViewModel class in the UXPage resources and name it HotelPageViewModel.
    XAML
    Copy Code
    <Intersoft:UXPage.Resources>
        <ViewModels:HotelPageViewModel x:Key="HotelPageViewModel" />
        ...
    </Intersoft:UXPage.Resources>
    <Grid x:Name="LayoutRoot" ... DataContext="{StaticResource HotelPageViewModel}">
    </Grid>
  3. Create a DataTemplate to define the item template for the UXListBox. Add the ImageLoader control that represents the user interface to display the hotel image, and bind these controls to the ViewModel through the provided properties, such as shown in the following example.
    XAML
    Copy Code
    <Intersoft:UXPage.Resources>
        ...
        <DataTemplate x:Key="HotelListTemplate">
            <Grid>
                <Intersoft:ImageLoader ImageSource="{Binding Hotel.Image}" Width="55" 
                                        ToolTipService.ToolTip="{Binding Hotel.Name}" ToolTipService.Placement="Right" />
            </Grid>
        </DataTemplate>
    </Intersoft:UXPage.Resources>
    
    <Intersoft:UXListBox ItemTemplate="{StaticResource HotelListTemplate}" ... />
  4. Bind the ItemsSource and SelectedItem.
    XAML
    Copy Code
    <Intersoft:UXListBox Name="HotelList" Background="Black" ItemTemplate="{StaticResource HotelListTemplate}" 
                        ItemsSource="{Binding HotelCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" 
                        SelectionChanged="UXListBox_SelectionChanged" />

  5. Bind CallOut DataContext with SelectedItem and bind all the control inside as shown in the following code.
    XAML
    Copy Code
    <Intersoft:CallOut... DataContext="{Binding SelectedItem}" >
        <Intersoft:CallOut.Background>
            <ImageBrush... ImageSource="{Binding Hotel.Image}" />
        </Intersoft:CallOut.Background>
        <Border VerticalAlignment="Bottom">
            <StackPanel VerticalAlignment="Center" Margin="40,0,0,0">
                <TextBlock... Text="{Binding Hotel.Name}" />
                <TextBlock... Text="{Binding Hotel.Location}" />
            </StackPanel>
        </Border>
    </Intersoft:CallOut>
  6. Bind CallOut TargetElement property to SelectedElement with ElemenetName set to HotelList.
    C#
    Copy Code
    <Intersoft:CallOut     TargetElement="{Binding SelectedElement, ElementName=HotelList}"     >    ...</Intersoft:CallOut>
  7. Finally, save and run the project.

After the application is running in the browser, you can try to click on the UXListBox item to change the data context of CallOut, such as shown in the following figure.

Conclusion

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 UXListBox to a collection of data, and then bind the CallOut data context to a SelectedItem in the ViewModel which performs data source changes that automatically reflect the data presented in CallOut.

Complete Code Listing

This section lists the complete code used in this walkthrough.

Hotel.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 DisItemDtailUsingRichUICtrlWithMVVMPat.ViewModels;
using System.Xml.Linq;

namespace DisItemDtailUsingRichUICtrlWithMVVMPat.Models
{
    public class Hotel : ModelBase
    {
        private string _name;
        private string _location;
        private string _rating;
        private string _rate;
        private string _image;

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

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

        public string Rating
        {
            get { return this._rating; }
            set {
                if (this._rating != value) {
                    this._rating = value;
                    OnPropertyChanged("Rating");
                }
            }
        }
        
        public string Rate
        {
            get { return this._rate; }
            set
            {
                if (this._rate != value)
                {
                    this._rate = value;
                    OnPropertyChanged("Rate");
                }
            }
        }

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

        public Hotel(XElement x)
        {
            this._name = x.Element("Name").Value.Trim();
            this._location = x.Element("Location").Value.Trim();
            this._rating = x.Element("Rating").Value.Trim();
            this._rate = x.Element("Rate").Value.Trim();
            this._image = x.Element("Image").Value.Trim();
        }
    }
}

HotelItemViewModel.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 DisItemDtailUsingRichUICtrlWithMVVMPat.Models;

namespace DisItemDtailUsingRichUICtrlWithMVVMPat.ViewModels
{
    public class HotelItemViewModel : ViewModelBase
    {
        private Hotel _hotel;
        private string _id;

        public HotelItemViewModel(Hotel hotel)
        {
            this._hotel = hotel;
        }

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

        public Hotel Hotel
        {
            get { return this._hotel; }
            set {
                if (this._hotel != null) {
                    this._hotel = value;
                    OnPropertyChanged("Hotel");
                }
            }
        }
    }
}

HotelPageViewModel.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.Windows.Resources;
using System.Xml.Linq;
using DisItemDtailUsingRichUICtrlWithMVVMPat.Models;
using System.Linq;

namespace DisItemDtailUsingRichUICtrlWithMVVMPat.ViewModels
{
    public class HotelPageViewModel : ViewModelBase
    {
        private ObservableCollection<HotelItemViewModel> _hotelCollection;
        private HotelItemViewModel _selectedItem;

        public HotelPageViewModel()
        {
            this.LoadHotel();
        }

        public ObservableCollection<HotelItemViewModel> HotelCollection
        {
            get { return this._hotelCollection; }
            set
            {
                if (this._hotelCollection != value) {
                    this._hotelCollection = value;
                    OnPropertyChanged("HotelCollection");                
                }
            }
        }

        public HotelItemViewModel SelectedItem
        {
            get { return this._selectedItem; }
            set {
                if (this._selectedItem != value) {
                    this._selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                }
            }
        }

        public void LoadHotel()
        {
            StreamResourceInfo stream = System.Windows.Application.GetResourceStream(new Uri("/DisItemDtailUsingRichUICtrlWithMVVMPat;component/SampleData/HotelDataSource.xml", UriKind.Relative));
            XDocument doc = XDocument.Load(stream.Stream);
            var hotels = doc.Descendants("Hotel").Select(a => new Hotel(a));
            _hotelCollection = new ObservableCollection<HotelItemViewModel>();
            int i = 0;
            foreach (var dt in hotels)
            {
                dt.Image = "/DisItemDtailUsingRichUICtrlWithMVVMPat;component/Images/Hotels/" + dt.Image;
                HotelItemViewModel newData = new HotelItemViewModel(dt);
                newData.Id = i.ToString();
                HotelCollection.Add(newData);
                i++;
            }
            stream.Stream.Close();
        }
    }
}

HotelPage.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:DisItemDtailUsingRichUICtrlWithMVVMPat.ViewModels"
        mc:Ignorable="d"
        x:Class="DisItemDtailUsingRichUICtrlWithMVVMPat.Views.HotelPage" 
        Title="UXPage1 Page"
        d:DesignWidth="640" d:DesignHeight="480">
        
    <Intersoft:UXPage.Resources>
        <ViewModels:HotelPageViewModel x:Key="HotelPageViewModel" />
        
        <DataTemplate x:Key="HotelListTemplate">
            <Grid>
                <Intersoft:ImageLoader ImageSource="{Binding Hotel.Image}" Width="55" 
                                       ToolTipService.ToolTip="{Binding Hotel.Name}" ToolTipService.Placement="Right" />
            </Grid>
        </DataTemplate>
    </Intersoft:UXPage.Resources>

    <Grid x:Name="LayoutRoot" Background="{x:Null}" Width="640" Height="480" DataContext="{StaticResource vwHotel}">
        <Border CornerRadius="20">
            <Border.Background>
                <LinearGradientBrush>
                    <GradientStop Color="Gray" Offset="0.5" />
                    <GradientStop Color="LightGray" Offset="1" />
                </LinearGradientBrush>
            </Border.Background>
            <Border.Effect>
                <DropShadowEffect Color="Gray" />
            </Border.Effect>
            <Intersoft:DockPanel FillChildMode="Custom">
                <Intersoft:GlassLabel Content="Hotel" Intersoft:DockPanel.Dock="Top" SpreadBackground="Gray" />
                <Intersoft:UXScroller Intersoft:DockPanel.Dock="Left" Margin="10 10 0 10">
                    <Intersoft:UXListBox Name="HotelList" Background="Black" ItemTemplate="{StaticResource HotelListTemplate}" 
                                         ItemsSource="{Binding HotelCollection}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" 
                                         />
                </Intersoft:UXScroller>
                
                <Intersoft:CallOut Name="HotelCallOut" Visibility="Visible" Intersoft:DockPanel.IsFillElement="True" 
                                   DataContext="{Binding SelectedItem}" StrokeThickness="0" CornerRadius="10" 
                                   Grid.Column="1" PointerPosition="Left" PointerPoint1="12, 0" PointerPoint2="0,20" PointerPoint3="-12, 0" 
                                   Margin="0 20 20 20" TargetElement="{Binding SelectedElement, ElementName=HotelList}">
                    <Intersoft:CallOut.Background>
                        <ImageBrush Stretch="UniformToFill" ImageSource="{Binding Hotel.Image}" />
                    </Intersoft:CallOut.Background>
                    <Border VerticalAlignment="Bottom">
                        <StackPanel VerticalAlignment="Center" Margin="40,0,0,0">
                            <TextBlock Text="{Binding Hotel.Name}" Foreground="White" FontSize="26.667"/>
                            <TextBlock Text="{Binding Hotel.Location}" Foreground="White" FontSize="18.667"/>
                        </StackPanel>
                    </Border>
                </Intersoft:CallOut>
            </Intersoft:DockPanel>
        </Border>
        </Grid>
</Intersoft:UXPage>
See Also

Concepts

Other Resources