Intersoft ClientUI Documentation
Walkthrough: Use UXSearchBox to Show Search Results in Different Container with MVVM Pattern

This walkthrough shows you how to create a UXSearchBox to search item and show the search result in a UXItemsControl. This walkthrough demonstrates the following concept:

Prerequisites

You need the following components to complete this walkthrough:

In addition, you also need the following resources to complete this walkthrough:

The assembly is required for the XML data source and images

Creating a new Intersoft ClientUI MVVM 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.
  4. Also add reference to the Intersoft.ClientUI.Samples.Assets assembly, the assembly is available from the provided ClientUI sample.

Creating The Model Class

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

To create the Book model class

  1. Create a new Book.cs under the Models folder and inherit the ModelBase class.
  2. Create a private variable and a public property for Author node with a String data type. In the setter property, OnPropertyChanged method must be called after the property is assigned a new value.
    Sample Code
    Copy Code
    private string _author;
    
    public string Author
    {
        get
        {
            return _author;
        }
        set
        {
            if (_author != value)
            {
                _author = value;
                OnPropertyChanged("Author");
            }
        }
    }
  3. Repeat the process for ID, Title, Category, Price, and Image node. String data type is used for ID, Title, and Category. Double is used for Price. Uri is used for Image.
  4. Create a constructor which accept XElement parameter. The constructor maps information in the data entity to each property in the class.
    Sample Code
    Copy Code
    public Book(XElement x)
        : this()
    {
        this._author = x.Element("Author").Value.Trim();
        this._title = x.Element("Title").Value.Trim();
        this._category = x.Element("Category").Value.Trim();
        this._ID = x.Element("ID").Value.Trim();
        this._price = double.Parse(x.Element("Price").Value.Trim());
        this._image = new Uri("/Intersoft.ClientUI.Samples.Assets;component/Images/Books/" + x.Element("Image").Value.Trim(), UriKind.RelativeOrAbsolute);
    }

Creating the ViewModel

This section shows how to create a ViewModel to hold the collection of Book model object. In order to implement search, the UXSearchBox requires IsSearching, QueryText and SearchResult property.

  1. Create a new BookListViewModel.cs under the ViewModels folder and inherit the ViewModelBase class.
  2. Create a public property to hold the collection of all the Book model object and the search result Book model object. The property which hold the search result need to call OnPropertyChanged method in the setter.
    Sample Code
    Copy Code
    public ObservableCollection<Book> Books { get; set; }
    
    private ObservableCollection<Book> _searchResult;
    
    public ObservableCollection<Book> SearchResult
    {
        get { return this._searchResult; }
        set
        {
            if (this._searchResult != value)
            {
                this._searchResult = value;
                this.OnPropertyChanged("SearchResult");
            }
        }
    }
  3. Create a property to hold the query text inputted in the UXSearchBox.
    Sample Code
    Copy Code
    private string _queryText; 
    
    public string QueryText
    {
        get { return this._queryText; }
        set
        {
            if (this._queryText != value)
            {
                this._queryText = value;
                if (string.IsNullOrEmpty(value))
                    this.DoSearch();
    
                this.OnPropertyChanged("QueryText");
            }
        }
    }
  4. Create a LoadBooks method which will be invoked in the constructor to load the Book entity from the XML file to the Book collection and search result variable.
    Sample Code
    Copy Code
    public BookListViewModel()
    {
        this.LoadBooks();
    }
    
    private void LoadBooks()
    {
        // loads book data from xml file
        StreamResourceInfo resource = System.Windows.Application.GetResourceStream(new Uri("Intersoft.ClientUI.Samples.Assets;component/Data/BookDataSource.xml", UriKind.Relative));
    
        XDocument doc = XDocument.Load(resource.Stream);
    
        var books = from x in doc.Descendants("Book")
            select new Book(x);
    
        this.Books = new ObservableCollection<Book>();
    
        foreach (Book book in books)
        {
            this.Books.Add(book);
        }
    
        this.SearchResult = this.Books;
    
        resource.Stream.Close();
    }
  5. Create a property to indicate the searching status of the UXSearchBox. Assigning a new value to this property triggers the searching logic. The searching logic is implemented in the next step using a method.
    Sample Code
    Copy Code
    private bool _isSearching;
    
    public bool IsSearching
    {
        get { return this._isSearching; }
        set
        {
            if (this._isSearching != value)
            {                    
                this._isSearching = value;
                this.OnPropertyChanged("IsSearching");
                this.DoSearch();
            }
        }
    }
  6. Create a method to implements the searching logic.
    Sample Code
    Copy Code
    private void DoSearch()
    {
        if (!string.IsNullOrEmpty(this.QueryText))
        {
            var query = from q in this.Books
                where q.Title.ToLower(CultureInfo.InvariantCulture).Contains(this.QueryText.ToLower(CultureInfo.InvariantCulture))
                select q;
    
            ObservableCollection data = new ObservableCollection();
            foreach (Book d in query)
            {
                data.Add(d);
            }
    
            this.SearchResult = data;
            this.IsSearching = false;
        }
        else
        {
            this.SearchResult = this.Books;
        }
    }

Creating the View

This section describes how to create the BookList view which contains the UXSearchBox and UXItemsControl. The UXItemsControl is used to hold the search result.

To create the BookList view

  1. Add a new UXPage to the Views folder in your Silverlight project and name it BookList.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. Declare the namespace that maps to the BookListViewModel class.
    XAML
    Copy Code
    <Intersoft:UXPage 
            ...
        xmlns:ViewModels="clr-namespace:ClientUIMVVMSearchBox.ViewModels"
            ...
        >
        ...
    </Intersoft:UXPage>
  3. Set the page DataContext to BooksViewModel.
    XAML
    Copy Code
    <Intersoft:UXPage.DataContext>
        <Assets:BookListViewModel/>
    </Intersoft:UXPage.DataContext>
  4. Modify the LayoutRoot control to use DockPanel and set the FillChildMode property to Custom.
  5. Add a new UXSearchBox. Set the following properties:
    Property Value
    Intersoft:DockPanel.Dock Top
    Width 250
    HorizontalAlignment Right
    Locate the IsSearching 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 IsSearching
    4. From the Tab Options, set Mode to TwoWay
    Locate the QueryText 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 QueryText 
    4. From the Tab Options, set Mode to TwoWay
    XAML
    Copy Code
    <Intersoft:UXSearchBox Intersoft:DockPanel.Dock="Top" Width="250" IsSearching="{Binding IsSearching, Mode=TwoWay}" QueryText="{Binding QueryText, Mode=TwoWay}" HorizontalAlignment="Right" />
  6. Add a new ScrollViewer and set the DockPanel IsFillElement to True.
  7. Add a new UXItemsControl under the ScrollViewer. Set the following property:
    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 SearchResult
  8. Modify the ItemsPanel property of UXItemsControl to use WrapPanel.
  9. Modify the ItemTemplate property of UXItemsControl to use a StackPanel with Image and EllipsisText. Set the following properties:
    Property Value
    StackPanel
    Width 80
    Margin 8
    Image
    Height 80
    Width 80
    ToolTipService.ToolTip {Binding Title, Mode=OneWay}
    EllipsisText
    EllipsisPosition Right
    Locate the Source property on the Image.
    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 Image
    Locate the Text property on the EllipsisText.
    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 Title
    XAML
    Copy Code
    <Intersoft:UXItemsControl ItemsSource="{Binding SearchResult}">
        <Intersoft:UXItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Intersoft:WrapPanel />
            </ItemsPanelTemplate>
        </Intersoft:UXItemsControl.ItemsPanel>
        <Intersoft:UXItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Width="80" Margin="8">
                    <Image Source="{Binding Image}" Height="80" Width="80" ToolTipService.ToolTip="{Binding Title, Mode=OneWay}"/>
                    <Intersoft:EllipsisText Text="{Binding Title}" EllipsisPosition="Right" />
                </StackPanel>
            </DataTemplate>
        </Intersoft:UXItemsControl.ItemTemplate>
    </Intersoft:UXItemsControl>

Viewing the Result

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

To view the result

  1. Try searching for mi in UXSearchBox.
  2. Only the Book containing the phrase mi in the Title will be shown.

Conclusion

In this walkthrough, you have learned how to create ClientUI MVVM Application project using Intersoft ClientUI MVVM Application project template, and create classes and page based on the MVVM pattern. You also learned how to utilize search feature in UXSearchBox to show the search result in UXItemsControl.

For more information about application development using MVVM pattern, see MVVM Pattern Overview. For more information about UXSearchBox control, see UXSearchBox Overview.

Complete Code Listing

This section lists the complete code used in this walkthrough.

BookListViewModel.cs

C#
Copy Code
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Resources;
using System.Xml.Linq;
using ClientUIMVVMSearchBox.Models;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;

namespace ClientUIMVVMSearchBox.ViewModels
{
    public class BookListViewModel : ViewModelBase
    {
        // Fields
        private bool _isSearching;
        private string _queryText;        
        private ObservableCollection<Book> _searchResult;        

        // Views        
        public ObservableCollection<Book> Books { get; set; }

        // Search
        public bool IsSearching
        {
            get { return this._isSearching; }
            set
            {
                if (this._isSearching != value)
                {                    
                    this._isSearching = value;
                    this.OnPropertyChanged("IsSearching");
                    this.DoSearch();
                }
            }
        }

        public string QueryText
        {
            get { return this._queryText; }
            set
            {
                if (this._queryText != value)
                {
                    this._queryText = value;
                    if (string.IsNullOrEmpty(value))
                        this.DoSearch();

                    this.OnPropertyChanged("QueryText");
                }
            }
        }

        public ObservableCollection<Book> SearchResult
        {
            get { return this._searchResult; }
            set
            {
                if (this._searchResult != value)
                {
                    this._searchResult = value;
                    this.OnPropertyChanged("SearchResult");
                }
            }
        }

        public BookListViewModel()
        {
            this.LoadBooks();
        }

        private void LoadBooks()
        {
            // loads book data from xml file
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(new Uri("Intersoft.ClientUI.Samples.Assets;component/Data/BookDataSource.xml", UriKind.Relative));

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

            var books = from x in doc.Descendants("Book")
                select new Book(x);

            this.Books = new ObservableCollection<Book>();

            foreach (Book book in books)
            {
                this.Books.Add(book);
            }

            this.SearchResult = this.Books;

            resource.Stream.Close();
        }

        private void DoSearch()
        {
            if (!string.IsNullOrEmpty(this.QueryText))
            {
                var query = from q in this.Books
                    where q.Title.ToLower(CultureInfo.InvariantCulture).Contains(this.QueryText.ToLower(CultureInfo.InvariantCulture))
                    select q;

                ObservableCollection<Book> data = new ObservableCollection<Book>();
                foreach (Book d in query)
                {
                    data.Add(d);
                }

                this.SearchResult = data;
                this.IsSearching = false;
            }
            else
            {
                this.SearchResult = this.Books;
            }
        }
    }
}

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

namespace ClientUIMVVMSearchBox.Models
{
    public class Book : ModelBase
    {
        public Book()
        {
        }

        public Book(XElement x)
            : this()
        {
            this._author = x.Element("Author").Value.Trim();
            this._title = x.Element("Title").Value.Trim();
            this._category = x.Element("Category").Value.Trim();
            this._ID = x.Element("ID").Value.Trim();
            this._price = double.Parse(x.Element("Price").Value.Trim());
            this._image = new Uri("/Intersoft.ClientUI.Samples.Assets;component/Images/Books/" + x.Element("Image").Value.Trim(), UriKind.RelativeOrAbsolute);
        }

        private Uri _image = null;
        private string _author;
        private string _title;
        private string _category;
        private string _ID;
        private double _price;

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

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

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

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

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

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

BookList.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"
        mc:Ignorable="d"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"
        xmlns:ViewModels="clr-namespace:ClientUIMVVMSearchBox.ViewModels"
        x:Class="ClientUIMVVMSearchBox.BookList" 
        Title="BookList Page"
        d:DesignWidth="640" d:DesignHeight="480">
        
    <Intersoft:UXPage.DataContext>
        <ViewModels:BookListViewModel />
    </Intersoft:UXPage.DataContext>
    
        <Intersoft:DockPanel x:Name="LayoutRoot" FillChildMode="Custom">
        <Intersoft:UXSearchBox Intersoft:DockPanel.Dock="Top" Width="250" IsSearching="{Binding IsSearching, Mode=TwoWay}" QueryText="{Binding QueryText, Mode=TwoWay}" HorizontalAlignment="Right" />
        <Intersoft:UXScrollViewer Intersoft:DockPanel.IsFillElement="True">
            <Intersoft:UXItemsControl ItemsSource="{Binding SearchResult}">
                <Intersoft:UXItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Intersoft:WrapPanel />
                    </ItemsPanelTemplate>
                </Intersoft:UXItemsControl.ItemsPanel>
                <Intersoft:UXItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Width="80" Margin="8">
                            <Image Source="{Binding Image}" Height="80" Width="80" ToolTipService.ToolTip="{Binding Title, Mode=OneWay}"/>
                            <Intersoft:EllipsisText Text="{Binding Title}" EllipsisPosition="Right" />
                        </StackPanel>
                    </DataTemplate>
                </Intersoft:UXItemsControl.ItemTemplate>
            </Intersoft:UXItemsControl>
        </Intersoft:UXScrollViewer>
    </Intersoft:DockPanel>
</Intersoft:UXPage>
See Also

Concepts

Other Resources