Intersoft ClientUI Documentation
Walkthrough: Create Rich Application using Windowing and MVVM Pattern

This walkthrough shows you how to create rich application using windowing and displaying data 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 Desktop Application Project

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

To create the ClientUI Desktop Application project

  1. Start Visual Studio 2010.
  2. Create a new ClientUI Desktop Application project using Intersoft ClientUI MVVM Application project template. To learn more, see Walkthrough: Create New Intersoft ClientUI Desktop 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\BookDataSource.xml.
  3. Click on the BookDataSource.xml file and press F4 to open the Property Window. Change the Build Action property to Resources.

To add the resources file

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

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

Creating Model Class

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

Next, you will create the view for your rich application using windowing.

Creating the View

The Intersoft ClientUI Desktop Application project template already provide a MainPage.xaml page that already contains a basic windowing application using UXDesktop, UXWindow and UXDesktopDock.

In this walkthrough you are going to create additional UXDesktopDockButton inside the UXDesktopDock to show collection of books and also a UXWindow to display the book details.

To add new UXDesktopDockButton

  1. Open MainPage.xaml
  2. Add UXDesktopDockButton control to UXDesktopDock control.
    Set the following properties to the control.
    Property Value
    Icon Assets/Dock/Books.png
    Text Books
    StackMode GridStyle
    StackGridMode DynamicGrid
    StackTotalDisplayItem 0
    StackGridItemWidth 128
    StackGridItemHeight 128
    AllowMoveItem True

    XAML
    Copy Code
    <Intersoft:UXDesktopDockButton Icon="Assets/Dock/Books.png" Text="Books"
                                    StackMode="GridStyle" StackGridMode="DynamicGrid" StackTotalDisplayItem="0"
                                    StackGridItemWidth="128" StackGridItemHeight="128" AllowMoveItem="True"                         
                                    />

To create BookDetails View

  1. In your project, add new Intersoft UXWindow with name BookDetails.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. Set the Icon property of UXWindow to ../Assets/Dock/Books.png.
  3. Add  DockPanel inside LayoutRoot Grid and set the FillChildMode property to Custom.
  4. Add UXToolBar inside the DockPanel
    Set the Intersoft:DockPanel.Dock property to Top and the OverflowHandleVisibility property to AsNeeded.
  5. Add UXToolGroup inside the UXToolBar.
  6. Add UXToolBarButton inside the UXToolGroup.
    Set the Content property to Save, the DisplayMode property to ContentAndImage and the Icon property to ../Assets/ToolBar/Save.png.
  7. Add UXSeparator inside the UXToolGroup.
  8. Add another UXToolBarButton inside the UXToolGroup.
    Set the Content property to Close, and the Command property to Intersoft:WindowCommands.Close.
    XAML
    Copy Code
    <Intersoft:UXWindow...>    <Grid x:Name="LayoutRoot">        <Intersoft:DockPanel FillChildMode="Custom">             <Intersoft:UXToolBar Intersoft:DockPanel.Dock="Top" OverflowHandleVisibility="AsNeeded">                <Intersoft:UXToolGroup>                    <Intersoft:UXToolBarButton Content="Save" DisplayMode="ContentAndImage" Icon="../Assets/ToolBar/Save.png" />                    <Intersoft:UXSeparator/>                    <Intersoft:UXToolBarButton Content="Close" Command="Intersoft:WindowCommands.Close"/>                </Intersoft:UXToolGroup>             </Intersoft:UXToolBar>        </Intersoft:DockPanel>    </Grid></Intersoft:UXWindow>

  9. Add another UXToolGroup inside the UXToolBar and set the Placement property to RightOrBottom.
    XAML
    Copy Code
    <Intersoft:UXToolGroup Placement="RightOrBottom">
    </Intersoft:UXToolGroup>
  10. Add UXCallOut control to the new UXToolGroup.
    Set the DisplayAnimation property to Fly, the PreferredPosition property to Right and the MouseLeaveAction property to HidePopup.
    XAML
    Copy Code
        <Intersoft:UXCallOut DisplayAnimation="Fly" PreferredPosition="Right" MouseLeaveAction="HidePopup">
        </Intersoft:UXCallOut>
  11. Add StylishLabel control to the UXCallOut.Header and set the following properties.
    Property Value
    ImageSource ../Assets/Images/Information.png
    Content About this template
    ContentType ContentAndImage
    Style {StaticResource SimpleLabelStyle}

    XAML
    Copy Code
    <Intersoft:UXCallOut... >    <Intersoft:UXCallOut.Header>        <Intersoft:StylishLabel ImageSource="../Assets/Images/Information.png" Content="About this template"                             ContentType="ContentAndImage" Style="{StaticResource SimpleLabelStyle}"/>    </Intersoft:UXCallOut.Header></Intersoft:UXCallOut>

  12. Add TextBlock control after UXCallOut.Header as the content of UXCallOut and set the following properties.
    Property Value
    TextWrapping Wrap
    Margin 4
    Width 300
    Text This template uses MVVM pattern to consistently perform data binding based on the available DataContext. The data fields shown in this template are automatically populated from the datasource assigned in StartupParameters which is passed from the LaunchApplication routed command.

    XAML
    Copy Code
    <Intersoft:UXToolGroup... >
        <Intersoft:UXCallOut... >
            <Intersoft:UXCallOut.Header>
                ...
            </Intersoft:UXCallOut.Header>
            <TextBlock TextWrapping="Wrap" Margin="4" Width="300" 
                        Text="This template uses MVVM pattern to consistently perform data binding based on the available DataContext. The data fields shown in this template are automatically populated from the datasource assigned in StartupParameters which is passed from the LaunchApplication routed command."/>
        </Intersoft:UXCallOut>
    </Intersoft:UXToolGroup>
  13. Add ContentReflector control and set the following properties.
    Property Value
    HorizontalAlignment Left
    Width 160
    VerticalContentAlignment Bottom
    Margin 12

    XAML
    Copy Code
    <Intersoft:ContentReflector HorizontalAlignment="Left" Width="160" VerticalContentAlignment="Bottom" Margin="12">
    </Intersoft:ContentReflector>
  14. Add Image control to the ContentReflector control.
    XAML
    Copy Code
    <Intersoft:ContentReflector... >
        <Image />
    </Intersoft:ContentReflector>
  15. Add StackPanel after ContentReflector.
    Set the Intersoft:DockPanel.Dock property to Right and the Intersoft:DockPanel.IsFillElement property to True.
    XAML
    Copy Code
    <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
    </StackPanel>
  16. Add ExpandableGroupBox control to the StackPanel.
    Set the Header property to General Information and the VerticalAlignment property to Top.
    XAML
    Copy Code
    <StackPanel... >
        <Intersoft:ExpandableGroupBox Header="General Information" VerticalAlignment="Top">
        </Intersoft:ExpandableGroupBox>
    </StackPanel>

  17. Add UXItemsControl control to the ExpandableGroupBox and set the ItemContainerStyle property to {StaticResource FieldLabelStyle}.
    XAML
    Copy Code
    <Intersoft:ExpandableGroupBox... >
        <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
        </Intersoft:UXItemsControl>
    </Intersoft:ExpandableGroupBox>
  18. Add FieldLabel control to the UXItemsControl and set the Header property to ID.
    XAML
    Copy Code
    <Intersoft:UXItemsControl... >
        <Intersoft:FieldLabel Header="ID">
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>

  19. Add UXTextBox control to the FieldLabel control and set the IsEnabled property to False and the Style property to {StaticResource SimpleTextBoxStyle}.
    XAML
    Copy Code
    <Intersoft:FieldLabel... >
        <Intersoft:UXTextBox Text="" IsEnabled="False" Style="{StaticResource SimpleTextBoxStyle}" />
    </Intersoft:FieldLabel>

  20. Add more FieldLabel and UXTextBox control by repeating step 18 and 19.
    XAML
    Copy Code
    <Intersoft:UXItemsControl... >
        <Intersoft:FieldLabel Header="ID">
            <Intersoft:UXTextBox Text="" IsEnabled="False" Style="{StaticResource SimpleTextBoxStyle}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Title">
            <Intersoft:UXTextBox Text="" Style="{StaticResource SimpleTextBoxStyle}"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Author">
            <Intersoft:UXTextBox Text="" Style="{StaticResource SimpleTextBoxStyle}"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Category">
            <Intersoft:UXTextBox Text="{}" Style="{StaticResource SimpleTextBoxStyle}"/>
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Price">
            <Intersoft:UXTextBox Text="{Binding BookItem.Book.Price}" Style="{StaticResource SimpleTextBoxStyle}"/>
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>

     

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

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 BookCollection to represent an observable collection of BookItemViewModel and a DelegateCommand to represent the view command which is used to show a message box.

To create the BookItemViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name BookItemViewModel.
  3. At BookItemViewModel, inherit the BookItemViewModel class from ViewModelBase class.
    C#
    Copy Code
    public class BookItemViewModel : ViewModelBase
    {
    }
  4. In BookItemViewModel, create the Book and CommandParameter property along with constructor to accept the Book model as its parameter. 
    C#
    Copy Code
    public class BookItemViewModel : ViewModelBase
    {
        private Book _book;
        private WindowOptions _parameter;
    
        public BookItemViewModel(Book book)
        {
            this._book = book;
            _parameter = new WindowOptions()
            {
                Uri = new Uri("/Views/BookDetails.xaml", UriKind.Relative),
                ForceSingleInstance = true,
                StartupParameters = this._book,
                WindowName = "wndBook_" + this._book.ID
            };
        }
    
        public Book Book {
            get { return this._book; }
            set {
                if (this._book != value) {
                    this._book = value;
                    OnPropertyChanged("Book");                
                }
            }
        }
    
        public WindowOptions CommandParameter {
            get { return _parameter; }
        }
    }    

To create the BookViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name BookViewModel.
  3. At BookViewModel, inherit BookViewModel class from ViewModelBase class.
    C#
    Copy Code
    public class BookViewModel : ViewModelBase
    {
    }
  4. In BookViewModel, add the BookCollection, and Book properties along with a LoadBooks method to extract the data from the xml file.
    C#
    Copy Code
    public class BookViewModel : ViewModelBase
    {
        private ObservableCollection<BookItemViewModel> _bookCollection;
        private BookItemViewModel _book;
    
        public BookViewModel()
        {
            this.LoadBooks();
        }
        public ObservableCollection<BookItemViewModel> BookCollection
        {
            get { return this._bookCollection; }
            set {
                if (this._bookCollection != value) {
                    this._bookCollection = value;
                    OnPropertyChanged("BookCollection");                
                }
            }
        }
        public BookItemViewModel Book
        {
            get { return this._book; }
            set {
                if (this._book != value) {
                    this._book = value;
                    OnPropertyChanged("Book");                
                }
            }
        }
    
        private void LoadBooks()
        {
            _bookCollection = new ObservableCollection<BookItemViewModel>();
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(new Uri("/CreateRIAUsingWindowingAndMVVMPattern;component/SampleData/BookDataSource.xml", UriKind.Relative));
            XDocument doc = XDocument.Load(resource.Stream);
            var books = from x in doc.Descendants("Book") select new Book(x);
            foreach (var dt in books) {
                dt.Image = "/CreateRIAUsingWindowingAndMVVMPattern;component/Assets/Images/Books/" + dt.Image;
                this.BookCollection.Add(new BookItemViewModel(dt));
            }
            resource.Stream.Close();
        }
    }

To create the BookDetailsViewModel

  1. In your project, locate the ViewModels folder.
  2. In ViewModels folder, add new class with name BookDetailsViewModel.
  3. At BookDetailsViewModel, inherit the BookDetailsViewModel from ViewModelBase class.
    C#
    Copy Code
    public class BookVDetailsiewModel : ViewModelBase
    {
    }
  4. In BookDetailsViewModel, create a constructor and add the BookItem property along with a DelegateCommand named SaveCommand.
    C#
    Copy Code
    public class BookDetailsViewModel : ViewModelBase
        {
            private BookItemViewModel _bookItem;
            private DelegateCommand _saveCommand = null;
    
            public BookDetailsViewModel(BookItemViewModel bookItem)
            {
                this._bookItem = bookItem;
                _saveCommand = new DelegateCommand(ExecuteSave, CanExecuteSave);
            }
    
            public DelegateCommand SaveCommand
            {
                get { return _saveCommand; }
            }
    
            public BookItemViewModel BookItem
            {
                get { return _bookItem; }
                set {
                    if (this._bookItem != value) {
                        this._bookItem = value;
                        OnPropertyChanged("BookItem");                
                    }
                }
            }
    
            private bool CanExecuteSave(object parameter)
            {
                return true;
            }
    
            private void ExecuteSave(object parameter)
            {
                MessageBoxServiceProvider.Show("Executing Save DelegateCommand...", "My DesktopApp",
                    Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK,
                    Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information,
                    null);
            }
        }

    The SaveCommand requires two method CanExecuteSave and ExecuteSave. The ExecuteSave contains the action when the command is executed. While the CanExecuteSave method contains a logical validation that determine when the command is active. Since we want the command to be always active we simple return true.

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 collection and command.

To bind the MainPage View to the BookViewModel class

  1. Declare the namespace that maps to the BookViewModel class in the MainPage page.
    XAML
    Copy Code
    <Intersoft:UXPage... 
        xmlns:ViewModels="clr-namespace:CreateRIAUsingWindowingAndMVVMPattern.ViewModels">
    </Intersoft:UXPage>
  2. Instantiate a new instance of the BookViewModel class in the UXPage resources and name it BookViewModel.
    XAML
    Copy Code
    <Intersoft:UXPage...>
        <Intersoft:UXPage.Resources>
            <ViewModels:BookViewModel x:Key="BookViewModel" />
            ...
        </Intersoft:UXPage.Resources>
    </Intersoft:UXPage>
  3. Create style for the UXDesktopDockButton using UXStackMenuStyleSelector and apply binding to its property using ClientUI Property Binding. To learn more about Property Binding see Data Binding Overview.
    XAML
    Copy Code
    <Intersoft:UXPage...>
        <Intersoft:UXPage.Resources>
            ...
            <!-- BookStackItemStyleSelector -->
            <Intersoft:PropertyBinding x:Key="BookStackItemBinding">
                <Intersoft:PropertyBinding Property="CommandTarget" 
                                    Binding="{Binding ElementName=uxDesktop}"/>
                <Intersoft:PropertyBinding Property="CommandParameter" 
                                    Binding="{Binding CommandParameter}"/>
            </Intersoft:PropertyBinding>
    
            <Style x:Key="BookStackGridItemStyle" BasedOn="{StaticResource GridStyle_Base}" TargetType="Intersoft:UXStackItem">
                <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
            </Style>
    
            <Style x:Key="BookStackArcItemStyle" BasedOn="{StaticResource ArcStyle_Base}" TargetType="Intersoft:UXStackItem">
                <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
            </Style>
    
            <Style x:Key="BookStackMenuItemStyle" BasedOn="{StaticResource MenuStyle_Base}" TargetType="Intersoft:UXStackItem">
                <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
            </Style>
    
            <Intersoft:UXStackMenuStyleSelector x:Key="BookStackItemStyleSelector"
                                                              ArcStyle="{StaticResource BookStackArcItemStyle}"
                                                              GridStyle="{StaticResource BookStackGridItemStyle}"
                                                              MenuStyle="{StaticResource BookStackMenuItemStyle}"/>
        </Intersoft:UXPage.Resources>
    </Intersoft:UXPage>
  4. Bind BookCollection into UXDesktopDockButton that we have been created before and apply the style with the style we just created as well.
    XAML
    Copy Code
    <Intersoft:UXDesktopDockButton Icon="Assets/Dock/Books.png" Text="Books"
                                        DisplayMemberPath="Book.Title" ImageMemberPath="Book.Image"
                                        StackMode="GridStyle" StackGridMode="DynamicGrid" StackTotalDisplayItem="0"
                                        StackGridItemWidth="128" StackGridItemHeight="128" AllowMoveItem="True"
                                                                            ItemContainerStyleSelector="{StaticResource BookStackItemStyleSelector}"
                                        DataContext="{Binding BookCollection, Source={StaticResource BookViewModel}}"
                                        ItemsSource="{Binding}"/>

To bind the BookDetails View to the BookDetailsViewModel class

  1. First we must set this view DataContext when the page is loaded in BookDetails.xaml.cs.
    C#
    Copy Code
    public BookDetails()
    {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(BookDetails_Loaded);
    }
    void BookDetails_Loaded(object sender, RoutedEventArgs e)
    {
        this.DataContext = new BookDetailsViewModel(new BookItemViewModel((Book)this.StartupParameters));
    }
  2. Bind the Command property of the UXToolBarButton to the SaveCommand that defined in the BookDetailsViewModel.
    XAML
    Copy Code
    <Intersoft:UXToolBarButton... Command="{Binding SaveCommand}"/>
  3. Bind the Source property of the Image to the Image that defined in the BookDetailsViewModel.
    XAML
    Copy Code
    <Intersoft:ContentReflector... >
        <Image Source="{Binding BookItem.Book.Image}"/>
    </Intersoft:ContentReflector>
  4. Bind all Text property of the UXTextBox to the property defined in the BookDetailsViewModel, such as ID, Title, Author, Category, Price.
    XAML
    Copy Code
    <Intersoft:UXItemsControl... >
        <Intersoft:FieldLabel Header="ID">
            <Intersoft:UXTextBox... Text="{Binding BookItem.Book.ID}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Title">
            <Intersoft:UXTextBox... Text="{Binding BookItem.Book.Title}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Author">
            <Intersoft:UXTextBox... Text="{Binding BookItem.Book.Author}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Category">
            <Intersoft:UXTextBox... Text="{Binding BookItem.Book.Category}" />
        </Intersoft:FieldLabel>
        <Intersoft:FieldLabel Header="Price">
            <Intersoft:UXTextBox... Text="{Binding BookItem.Book.Price}" >
        </Intersoft:FieldLabel>
    </Intersoft:UXItemsControl>
  5. Finally, save and run the project.

After the application is running in the browser, you can try to click on the UXDesktopDockButton buttons it will show you a collection of Book.


Try click one of the item to open the book details as shown in the figure below.


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 UXDesktopDockButton to a collection of data and show the selected data in new window.

To learn more about UI development using MVVM pattern, see MVVM Pattern Overview. To learn more about commanding, see Commanding Overview.

Complete Code Listing

This section lists the complete code used in this walkthrough.

Book.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 System.Xml.Linq;
using Intersoft.Client.Framework;

namespace CreateRIAUsingWindowingAndMVVMPattern.Models
{
    public class Book : ModelBase
    {
        private string _id;
        private string _image;
        private string _title;
        private string _author;
        private string _category;
        private decimal _price;

        public string ID {
            get { return _id; }
            set {
                if (this._id != value) {
                    _id = value;
                    OnPropertyChanged("ID");                
                }
            }
        }
        public string Image
        {
            get { return _image; }
            set
            {
                if (this._image != value) {
                    _image = value;
                    OnPropertyChanged("Image");                
                }
            }
        }
        public string Title
        {
            get { return _title; }
            set
            {
                if (this._title != value) {
                    _title = value;
                    OnPropertyChanged("Title");                
                }
            }
        }
        public string Author
        {
            get { return _author; }
            set
            {
                if (this._author != value) {
                    _author = value;
                    OnPropertyChanged("Author");
                }
            }
        }
        public string Category
        {
            get { return _category; }
            set
            {
                if (this._category != value) {
                    _category = value;
                    OnPropertyChanged("Category");                
                }
            }
        }
        public decimal Price
        {
            get { return _price; }
            set
            {
                if (this._price != value) {
                    _price = value;
                    OnPropertyChanged("Price");
                }
            }
        }

        public Book() { }
        public Book(XElement x)
        {
            this._id = x.Element("ID").Value.Trim();
            this._image = x.Element("Image").Value.Trim();
            this._title = x.Element("Title").Value.Trim();
            this._author = x.Element("Author").Value.Trim();
            this._category = x.Element("Category").Value.Trim();
            this._price = decimal.Parse(x.Element("Price").Value);
        }
    }
}

BookItemViewModel.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 CreateRIAUsingWindowingAndMVVMPattern.Models;
using Intersoft.Client.Framework;

namespace CreateRIAUsingWindowingAndMVVMPattern.ViewModels
{
    public class BookItemViewModel : ViewModelBase
    {
        private Book _book;
        private WindowOptions _parameter;

        public BookItemViewModel(Book book)
        {
            this._book = book;
            _parameter = new WindowOptions()
            {
                Uri = new Uri("/Views/BookDetails.xaml", UriKind.Relative),
                ForceSingleInstance = true,
                StartupParameters = this._book,
                WindowName = "wndBook_" + this._book.ID
            };
        }

        public Book Book {
            get { return this._book; }
            set {
                if (this._book != value) {
                    this._book = value;
                    OnPropertyChanged("Book");                
                }
            }
        }

        public WindowOptions CommandParameter {
            get { return _parameter; }
        }
    }
}

BookViewModel.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 CreateRIAUsingWindowingAndMVVMPattern.Models;
using System.Collections.ObjectModel;
using System.Windows.Resources;
using System.Xml.Linq;
using System.Linq;
using Intersoft.Client.Framework;

namespace CreateRIAUsingWindowingAndMVVMPattern.ViewModels
{
    public class BookViewModel : ViewModelBase
    {
        private ObservableCollection<BookItemViewModel> _bookCollection;
        private BookItemViewModel _book;

        public BookViewModel()
        {
            this.LoadBooks();
        }
        public ObservableCollection<BookItemViewModel> BookCollection
        {
            get { return this._bookCollection; }
            set {
                if (this._bookCollection != value) {
                    this._bookCollection = value;
                    OnPropertyChanged("BookCollection");                
                }
            }
        }
        public BookItemViewModel Book
        {
            get { return this._book; }
            set {
                if (this._book != value) {
                    this._book = value;
                    OnPropertyChanged("Book");                
                }
            }
        }

        private void LoadBooks()
        {
            _bookCollection = new ObservableCollection<BookItemViewModel>();
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(new Uri("/CreateRIAUsingWindowingAndMVVMPattern;component/SampleData/BookDataSource.xml", UriKind.Relative));
            XDocument doc = XDocument.Load(resource.Stream);
            var books = from x in doc.Descendants("Book") select new Book(x);
            foreach (var dt in books) {
                dt.Image = "/CreateRIAUsingWindowingAndMVVMPattern;component/Assets/Images/Books/" + dt.Image;
                this.BookCollection.Add(new BookItemViewModel(dt));
            }
            resource.Stream.Close();
        }
    }
}

BookDetailsViewModel.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 CreateRIAUsingWindowingAndMVVMPattern.Models;
using Intersoft.Client.Framework;
using Intersoft.Client.Framework.Input;

namespace CreateRIAUsingWindowingAndMVVMPattern.ViewModels
{
    public class BookDetailsViewModel : ViewModelBase
    {
        private BookItemViewModel _bookItem;
        private DelegateCommand _saveCommand = null;

        public BookDetailsViewModel(BookItemViewModel bookItem)
        {
            this._bookItem = bookItem;
            _saveCommand = new DelegateCommand(ExecuteSave, CanExecuteSave);
        }

        public DelegateCommand SaveCommand
        {
            get { return _saveCommand; }
        }

        public BookItemViewModel BookItem
        {
            get { return _bookItem; }
            set {
                if (this._bookItem != value) {
                    this._bookItem = value;
                    OnPropertyChanged("BookItem");                
                }
            }
        }

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

        private void ExecuteSave(object parameter)
        {
            MessageBoxServiceProvider.Show("Executing Save DelegateCommand...", "My DesktopApp",
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxButton.OK,
                Intersoft.Client.UI.Aqua.UXDesktop.MessageBoxImage.Information,
                null);
        }
    }
}

MainPage.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:local="clr-namespace:CreateRIAUsingWindowingAndMVVMPattern"
    xmlns:SampleData="clr-namespace:Expression.Blend.SampleData.ContactsDataSource"
    xmlns:ViewModels="clr-namespace:CreateRIAUsingWindowingAndMVVMPattern.ViewModels"
        mc:Ignorable="d" 
        x:Class="CreateRIAUsingWindowingAndMVVMPattern.MainPage" 
        Title="Main Page"
        d:DesignWidth="1024" d:DesignHeight="768">
        <Intersoft:UXPage.Resources>
                <ViewModels:ContactsViewModel x:Key="ContactsViewModel"/>
        <ViewModels:BookViewModel x:Key="BookViewModel" />
        <Intersoft:PropertyBinding x:Key="ContactStackItemBinding">
                        <Intersoft:PropertyBinding Property="CommandTarget" 
                                Binding="{Binding ElementName=uxDesktop}"/>
                        <Intersoft:PropertyBinding Property="CommandParameter" 
                                Binding="{Binding CommandParameter}"/>
                </Intersoft:PropertyBinding>
                
                <Style x:Key="ContactStackGridItemStyle" BasedOn="{StaticResource GridStyle_Base}" TargetType="Intersoft:UXStackItem">
                        <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                        <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource ContactStackItemBinding}"/>
                </Style>
                
                <Style x:Key="ContactStackArcItemStyle" BasedOn="{StaticResource ArcStyle_Base}" TargetType="Intersoft:UXStackItem">
                        <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                        <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource ContactStackItemBinding}"/>
                </Style>
                
                <Style x:Key="ContactStackMenuItemStyle" BasedOn="{StaticResource MenuStyle_Base}" TargetType="Intersoft:UXStackItem">
                        <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
                        <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource ContactStackItemBinding}"/>
                </Style>
                
                <Intersoft:UXStackMenuStyleSelector x:Key="ContactStackItemStyleSelector"
                                                          ArcStyle="{StaticResource ContactStackArcItemStyle}"
                                                          GridStyle="{StaticResource ContactStackGridItemStyle}"
                                                          MenuStyle="{StaticResource ContactStackMenuItemStyle}"/>
                <!--
                        The ContactStackItemStyleSelector enables you to show the stack items using either
                        arc style, grid style or menu style with consistent appearance and behaviors.
                        
                        To try various stack item styles, change the StackMode of Contacts dock button.
                -->                                  

        <!-- BookStackItemStyleSelector -->
        <Intersoft:PropertyBinding x:Key="BookStackItemBinding">
            <Intersoft:PropertyBinding Property="CommandTarget" 
                                Binding="{Binding ElementName=uxDesktop}"/>
            <Intersoft:PropertyBinding Property="CommandParameter" 
                                Binding="{Binding CommandParameter}"/>
        </Intersoft:PropertyBinding>

        <Style x:Key="BookStackGridItemStyle" BasedOn="{StaticResource GridStyle_Base}" TargetType="Intersoft:UXStackItem">
            <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
            <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
        </Style>

        <Style x:Key="BookStackArcItemStyle" BasedOn="{StaticResource ArcStyle_Base}" TargetType="Intersoft:UXStackItem">
            <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
            <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
        </Style>

        <Style x:Key="BookStackMenuItemStyle" BasedOn="{StaticResource MenuStyle_Base}" TargetType="Intersoft:UXStackItem">
            <Setter Property="Command" Value="Intersoft:WindowCommands.LaunchApplication"/>
            <Setter Property="Intersoft:BindingFramework.PropertyBinding" Value="{StaticResource BookStackItemBinding}"/>
        </Style>

        <Intersoft:UXStackMenuStyleSelector x:Key="BookStackItemStyleSelector"
                                                          ArcStyle="{StaticResource BookStackArcItemStyle}"
                                                          GridStyle="{StaticResource BookStackGridItemStyle}"
                                                          MenuStyle="{StaticResource BookStackMenuItemStyle}"/>
    </Intersoft:UXPage.Resources>

        <Intersoft:UXPage.Style>
                <StaticResource ResourceKey="MainPageStyle"/>
        </Intersoft:UXPage.Style>

        <Grid x:Name="LayoutRoot" Background="Black">
        <Intersoft:ImageLoader ImageSource="/Assets/Images/ColorSwing.jpg" ProgressBarVerticalAlignment="Top" 
                               ProgressBarMargin="28" ImageStretch="UniformToFill"/>

                <Intersoft:UXHyperlinkButton x:Name="ClientUILink" HorizontalAlignment="Right" VerticalAlignment="Bottom" 
                                     TargetName="_blank" NavigateUri="http://www.clientui.com" 
                                                                         Style="{StaticResource ClientUILinkStyle}">
                        <Image Height="48" Source="Assets/Images/Powered_ClientUI.png" Width="139" 
                   HorizontalAlignment="Left" VerticalAlignment="Top"/>
                </Intersoft:UXHyperlinkButton>
        
                <Intersoft:UXDesktop x:Name="uxDesktop" Background="{x:Null}" TaskBar="{Binding ElementName=desktopDock, Mode=OneWay}">
                        <Intersoft:UXWindow x:Name="wndHome" Header="Welcome to My DesktopApp" CanMaximize="False" 
                                WindowStartupLocation="CenterScreen" Height="480" Width="640" IsClientVisible="True" 
                                IsActive="True" MinWidth="480" MinHeight="320" Icon="Assets/Images/Home.png">
                                <local:Welcome/>
                        </Intersoft:UXWindow>
                </Intersoft:UXDesktop>
        
                <Intersoft:UXDesktopDock x:Name="desktopDock" HorizontalAlignment="Left" VerticalAlignment="Top" 
                                 MinimizeButtonGroup="groupSeparator" AllowReorderItem="True" AllowDropItem="True">
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/ClientUILogoLarge.png" Text="About My DesktopApp" ApplicationUri="/Views/About.xaml"/>
                        <Intersoft:UXDockSeparator Opacity="0.5"/>
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/HomeLarge.png" WindowName="wndHome" Text="Home"/>
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/TextEditLarge.png" Text="Notepad" ApplicationUri="/Views/Notepad.xaml"/>
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/ReportLarge.png" Text="Reports" NavigateUri="/Views/Reports.xaml"/>
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/SettingsLarge.png" Text="Settings" ApplicationUri="/Views/Settings.xaml"/>
                        <Intersoft:UXDockSeparator x:Name="groupSeparator" Opacity="0.5"/>

            <Intersoft:UXDesktopDockButton Icon="Assets/Dock/Books.png" Text="Books"
                                           DisplayMemberPath="Book.Title" ImageMemberPath="Book.Image"
                                           StackMode="GridStyle" StackGridMode="DynamicGrid" StackTotalDisplayItem="0"
                                           StackGridItemWidth="128" StackGridItemHeight="128" AllowMoveItem="True"
                                                                                   ItemContainerStyleSelector="{StaticResource BookStackItemStyleSelector}"
                                           DataContext="{Binding BookCollection, Source={StaticResource BookViewModel}}"
                                           ItemsSource="{Binding}"/>            
            
            <Intersoft:UXDesktopDockButton Icon="Assets/Dock/GroupFolderLarge.png" Text="Contacts"
                                           DisplayMemberPath="Contact.Name" ImageMemberPath="Contact.Photo"
                                           StackMode="GridStyle" StackGridMode="DynamicGrid" StackTotalDisplayItem="0"
                                           StackGridItemWidth="128" StackGridItemHeight="128" AllowMoveItem="True"
                                                                                   ItemContainerStyleSelector="{StaticResource ContactStackItemStyleSelector}"
                                           DataContext="{Binding Contacts, Source={StaticResource ContactsViewModel}}"
                                           ItemsSource="{Binding}"/>
            
                        <Intersoft:UXDesktopDockButton Icon="Assets/Dock/DownloadsFolderLarge.png" Text="Downloads" AllowMoveItem="True">
                                <Intersoft:UXStackItem Text="Development Roadmap" Icon="/Assets/Files/doc.png"/>
                                <Intersoft:UXStackItem Text="Product Overview" Icon="/Assets/Files/html.png"/>
                                <Intersoft:UXStackItem Text="Monthly Report" Icon="/Assets/Files/pdf.png"/>
                                <Intersoft:UXStackItem Text="Archived Files" Icon="/Assets/Files/zip.png"/>
                                <Intersoft:UXStackItem Text="Sales Notes" Icon="/Assets/Files/txt.png"/>
                                <Intersoft:UXStackItem Text="Tutorial Intro Voices" Icon="/Assets/Files/mp3.png"/>
                        </Intersoft:UXDesktopDockButton>
            
                </Intersoft:UXDesktopDock>
        </Grid>
</Intersoft:UXPage>

BookDetails.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"
        mc:Ignorable="d"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
        x:Class="CreateRIAUsingWindowingAndMVVMPattern.Views.BookDetails"
    Icon="../Assets/Dock/Books.png"
        Header="BookDetails"
        d:DesignWidth="640" d:DesignHeight="480">
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel FillChildMode="Custom">
            <Intersoft:UXToolBar Intersoft:DockPanel.Dock="Top" OverflowHandleVisibility="AsNeeded">
                <Intersoft:UXToolGroup>
                    <Intersoft:UXToolBarButton Content="Save" DisplayMode="ContentAndImage" Icon="../Assets/ToolBar/Save.png" Command="{Binding SaveCommand}"/>
                    <Intersoft:UXSeparator/>
                    <Intersoft:UXToolBarButton Content="Close" Command="Intersoft:WindowCommands.Close"/>
                </Intersoft:UXToolGroup>

                <Intersoft:UXToolGroup Placement="RightOrBottom">
                    <Intersoft:UXCallOut DisplayAnimation="Fly" PreferredPosition="Right" MouseLeaveAction="HidePopup">
                        <Intersoft:UXCallOut.Header>
                            <Intersoft:StylishLabel ImageSource="../Assets/Images/Information.png" Content="About this template" 
                                                    ContentType="ContentAndImage" Style="{StaticResource SimpleLabelStyle}"/>
                        </Intersoft:UXCallOut.Header>
                        <TextBlock TextWrapping="Wrap" Margin="4" Width="300" 
                                   Text="This template uses MVVM pattern to consistently perform data binding based on the available DataContext. The data fields shown in this template are automatically populated from the datasource assigned in StartupParameters which is passed from the LaunchApplication routed command."/>
                    </Intersoft:UXCallOut>
                </Intersoft:UXToolGroup>
            </Intersoft:UXToolBar>

            <Intersoft:ContentReflector HorizontalAlignment="Left" Width="160" VerticalContentAlignment="Bottom" Margin="12">
                <Image Source="{Binding BookItem.Book.Image}"/>
            </Intersoft:ContentReflector>

            <StackPanel Intersoft:DockPanel.Dock="Right" Intersoft:DockPanel.IsFillElement="True">
                <Intersoft:ExpandableGroupBox Header="General Information" VerticalAlignment="Top">
                    <Intersoft:UXItemsControl ItemContainerStyle="{StaticResource FieldLabelStyle}">
                        <Intersoft:FieldLabel Header="ID">
                            <Intersoft:UXTextBox Text="{Binding BookItem.Book.ID}" IsEnabled="False" Style="{StaticResource SimpleTextBoxStyle}" />
                        </Intersoft:FieldLabel>
                        <Intersoft:FieldLabel Header="Title">
                            <Intersoft:UXTextBox Text="{Binding BookItem.Book.Title}" Style="{StaticResource SimpleTextBoxStyle}"/>
                        </Intersoft:FieldLabel>
                        <Intersoft:FieldLabel Header="Author">
                            <Intersoft:UXTextBox Text="{Binding BookItem.Book.Author}" Style="{StaticResource SimpleTextBoxStyle}"/>
                        </Intersoft:FieldLabel>
                        <Intersoft:FieldLabel Header="Category">
                            <Intersoft:UXTextBox Text="{Binding BookItem.Book.Category}" Style="{StaticResource SimpleTextBoxStyle}"/>
                        </Intersoft:FieldLabel>
                        <Intersoft:FieldLabel Header="Price">
                            <Intersoft:UXTextBox Text="{Binding BookItem.Book.Price}" Style="{StaticResource SimpleTextBoxStyle}"/>
                        </Intersoft:FieldLabel>
                    </Intersoft:UXItemsControl>
                </Intersoft:ExpandableGroupBox>
            </StackPanel>
        </Intersoft:DockPanel>
    </Grid>
</Intersoft:UXWindow>
See Also

Concepts

Other Resources