Intersoft ClientUI Documentation
Walkthrough: Enable Drag-drop Functionality in UXListBox

This walkthrough shows how to drag and drop an object, which is triggered from images that are bound to DragDrop event.

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 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\ContactDataSource.xml.
  3. Click on the ContactDataSource.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 Photos.
  4. In Photos folder, copy the images from [Intersoft Installation Folder]\Intersoft WebUI Studio 2010 R1\Samples\SL4\ClientUI Samples\Intersoft.ClientUI.Samples.Assets\Images\Photos\].

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

Creating Model Class

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

Next, you will create the view for your simple contacts list application.

Creating the View

This section steps you through the process of creating a page that uses a variety of ClientUI controls such as UXListBox. The UXListBox is used to display a collection of Contact data.

To create the View

  1. In your project, locate Views folder.
  2. In Views folder, add new UXPage with name Contact.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
  3. Open Contact.xaml.
  4. Add a DockPanel. Set the VerticalAlignment and HorizontalAlignment property of DockPanel into Center.
  5. Add another DockPanel inside the previous DockPanel. Set the Width and Margin property of DockPanel into 270 and 4.
  6. Add the StylishLabel inside the DockPanel. Set the following properties of StylishLabel as below.
    Properties Value
    Content Available Personnel
    Intersoft:DockPanel.Dock Top
    HorizontalContentAlignment Left
  7. Add the UXSeparator. Set the Intersoft:DockPanel.Dock property of UXSeparator into Top.
  8. Add Grid. Set the Margin and Intersoft:DockPanel.IsFillElement property of Grid into 12 and True.
  9. Add the UXListBox inside the Grid. Set the following properties of UXListBox as below.
    Properties Value
    Height 300
    AllowDropItem True
    AllowMoveItem True
    AllowRemoveItem True
    HorizontalAlignment Stretch
    ItemContentType ContentAndImage
    ItemImageHeight 64
    ItemImageWidth 64

    XAML
    Copy Code
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Intersoft:DockPanel FillChildMode="Custom" Width="270" Margin="4">
                <Intersoft:StylishLabel Content="Available Personnel" Intersoft:DockPanel.Dock="Top" HorizontalContentAlignment="Left"/>
                <Intersoft:UXSeparator Intersoft:DockPanel.Dock="Top"/>
                <Grid Margin="12" Intersoft:DockPanel.IsFillElement="True">
                   <Intersoft:UXListBox Name="uXListBox1" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" />
                </Grid>
            </Intersoft:DockPanel>
        </Intersoft:DockPanel>
    </Grid>

  10. Repeat steps number 2-6. Set the Content property of StylishLabel into Out-Sourced Personnel.
    XAML
    Copy Code
    <Intersoft:DockPanel VerticalAlignment="Center" HorizontalAlignment="Center">
        ...
        <Intersoft:DockPanel FillChildMode="Custom" Width="270" Margin="4">
            <Intersoft:StylishLabel Content="Out-Sourced Personnel" Intersoft:DockPanel.Dock="Top" HorizontalContentAlignment="Left"/>
            <Intersoft:UXSeparator Intersoft:DockPanel.Dock="Top"/>
            <Grid Margin="12" Intersoft:DockPanel.IsFillElement="True">
                <Intersoft:UXListBox Name="uXListBox2" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" />
            </Grid>
        </Intersoft:DockPanel>
    </Intersoft:DockPanel>

Creating 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 items source and data context.

To create the ViewModel

  1. Add a new class to the ViewModels folder in your Silverlight project and name it ContactViewModel.cs.
  2. Open the ContactViewModel.cs and inherit the class from ViewModelBase class.
    C#
    Copy Code
    public class ContactViewModel : ViewModelBase { }
  3. In this view mode, you add the ContactsContactsData and OutsourceData which represent a collection of Contact.
    C#
    Copy Code
    // Fields
    private Contact _selectedItem = null;
    
    // Views
    public ObservableCollection<Contact> Contacts { get; set; }
    public ObservableCollection<Contact> ContactsData { get; set; }
    public ObservableCollection<Contact> OutsourceData { get; set; }
  4. Create a LoadData method to fill the Contact property based on the data from ContactDataSource.xml and invoke the method during object construction.
    C#
    Copy Code
    DragDropUXListBox public ContactViewModel()
    {
        this.LoadContacts();
    }
    
    private void LoadContacts()
    {
        // loads contact data from xml file
        StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
                new Uri("DragDropUXListBox;component/Assets/Data/ContactDataSource.xml", UriKind.Relative));
    
        XDocument doc = XDocument.Load(resource.Stream);
    
        var contacts = from x in doc.Descendants("Customer")
                        select new Contact(x);
    
        this.Contacts = new ObservableCollection<Contact>();
        this.ContactsData = new ObservableCollection<Contact>();
        this.OutsourceData = new ObservableCollection<Contact>();
    
        foreach (Contact contact in contacts)
        {
            contact.SetPhoto(this.Contacts.Count.ToString());
    
            this.Contacts.Add(contact);
                    this.ContactsData.Add(contact);
        }
    
        resource.Stream.Close();
    }

Binding The ViewModel Pattern to View Pattern

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, template and event.

To bind the ViewModel pattern

  1. In MainPage.xaml, locate the UXPage.Resource under UXPage.
  2. Instantiate a new instance of the ContactViewModel class in the UXPage resources and name it ContactsData.
    XAML
    Copy Code
    <Intersoft:UXPage.Resources>
        <ViewModels:ContactViewModel x:Key="ContactsData"/>
    </Intersoft:UXPage.Resources>
  3. In MainPage.xaml, locate the Grid under DockPanel.
  4. Bind the DataContext property of each Grid inside the DockPanel to the ConstactsData through the static resource extension markup.
    XAML
    Copy Code
    <Intersoft:DockPanel FillChildMode="Custom" Width="270" Margin="4">
        ...
        <Grid Margin="12" DataContext="{StaticResource ContactsData}" Intersoft:DockPanel.IsFillElement="True">
            ...
        </Grid>
    </Intersoft:DockPanel>
  5. In MainPage.xaml, locate the UXListBox under the first DockPanel.
  6. Bind the ItemsSource property of the UXListBox to the ConstactsData through the binding extension markup such as shown in the following example.
    XAML
    Copy Code
    <Grid Margin="12" DataContext="{StaticResource ContactsData}" Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:UXListBox Name="uXListBox1" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" SelectedValuePath="Id" ItemsSource="{Binding ContactsData}" IsTextSearchEnabled="True" DisplayMemberPath="Name" ImageMemberPath="Photo" />
    </Grid>
  7. In MainPage.xaml, locate the UXListBox under the second DockPanel.
  8. Bind the ItemsSource property of the second UXListBox to the OutsourceData through the binding extension markup such as shown in the following example.
    XAML
    Copy Code
    <Grid Margin="12" DataContext="{StaticResource ContactsData}" Intersoft:DockPanel.IsFillElement="True">
        <Intersoft:UXListBox Name="uXListBox2" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" SelectedValuePath="Id" ItemsSource="{Binding OutsourceData}" IsTextSearchEnabled="True" DisplayMemberPath="Name" ImageMemberPath="Photo" />
    </Grid>
  9. Run the project. Try to drag and drop the from Available list box into Out-sourced Personnel list box.

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 Attach the UXListBox to a DragDrop event in the ViewModel which can move the object into another UXListBox.

Complete Code Listing

This section lists the complete code used in this walkthrough.

Contact.cs

C#
Copy Code
using System;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using DragDropUXListBox.ViewModels;

namespace DragDropUXListBox.Models
{
    public class Contact : ModelBase
    {
        // rfc 2282 compliance email address regex
        private const string EmailPattern = @"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?";

        #region Constructors

        public Contact()
        {
        }

        public Contact(XElement x)
            : this()
        {
            this._id = x.Element("Id").Value.Trim();
            this._name = x.Element("Name").Value.Trim();
            this._email = x.Element("Email").Value.Trim();

            this._address = x.Element("Address").Value.Trim();
            this._state = x.Element("State").Value.Trim();
            this._zipCode = x.Element("ZipCode").Value.Trim();

            this._phone = x.Element("Phone").Value.Trim();
            this._fax = x.Element("Fax").Value.Trim();
            this._cell = x.Element("Cell").Value.Trim();

            this._blog = x.Element("Blog").Value.Trim();
            this._twitter = x.Element("Twitter").Value.Trim();
            this._website = x.Element("Website").Value.Trim();
        }

        #endregion

        #region Fields

        private string _name = string.Empty;
        private string _address = string.Empty;
        private string _phone = string.Empty;
        private string _cell = string.Empty;
        private string _id = string.Empty;
        private string _email = string.Empty;
        private string _fax = string.Empty;
        private string _blog = string.Empty;
        private string _twitter = string.Empty;
        private string _website = string.Empty;
        private string _state = string.Empty;
        private string _zipCode = string.Empty;
        private Uri _photo = null;

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                return this._name;
            }

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

        public string Address
        {
            get
            {
                return this._address;
            }

            set
            {
                if (this._address != value)
                {
                    this._address = value;
                    this.ClearError("Address");
                    this.OnPropertyChanged("Address");
                }
            }
        }

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

            set
            {
                if (this._phone != value)
                {
                    this._phone = value;
                    this.OnPropertyChanged("Phone");
                }
            }
        }

        public string Cell
        {
            get
            {
                return this._cell;
            }

            set
            {
                if (this._cell != value)
                {
                    this._cell = value;
                    this.OnPropertyChanged("Cell");
                }
            }
        }

        public string Id
        {
            get
            {
                return this._id;
            }

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

        public string Email
        {
            get
            {
                return this._email;
            }

            set
            {
                if (this._email != value)
                {
                    this._email = value;
                    this.OnPropertyChanged("Email");
                }
            }
        }

        public string Fax
        {
            get
            {
                return this._fax;
            }

            set
            {
                if (this._fax != value)
                {
                    this._fax = value;
                    this.OnPropertyChanged("Fax");
                }
            }
        }

        public string Blog
        {
            get
            {
                return this._blog;
            }

            set
            {
                if (this._blog != value)
                {
                    this._blog = value;
                    this.OnPropertyChanged("Blog");
                }
            }
        }

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

            set
            {
                if (this._twitter != value)
                {
                    this._twitter = value;
                    this.OnPropertyChanged("Twitter");
                }
            }
        }

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

            set
            {
                if (this._website != value)
                {
                    this._website = value;
                    this.OnPropertyChanged("Website");
                }
            }
        }

        public string State
        {
            get
            {
                return this._state;
            }

            set
            {
                if (this._state != value)
                {
                    this._state = value;
                    this.OnPropertyChanged("State");
                }
            }
        }

        public string ZipCode
        {
            get
            {
                return this._zipCode;
            }

            set
            {
                if (this._zipCode != value)
                {
                    this._zipCode = value;
                    this.ClearError("ZipCode");
                    this.OnPropertyChanged("ZipCode");
                }
            }
        }

        public Uri Photo
        {
            get
            {
                return this._photo;
            }

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

        }

        #endregion

        #region Methods

        public Contact Clone()
        {
            return new Contact()
            {
                Id = this._id,
                Name = this._name,
                Email = this._email,
                Address = this._address,
                State = this._state,
                ZipCode = this._zipCode,
                Phone = this._phone,
                Cell = this._cell,
                Fax = this._fax,
                Blog = this._blog,
                Twitter = this._twitter,
                Website = this._website,
                Photo = this._photo
            };
        }

        public bool Validate(bool notifyDataError)
        {
            bool isValid = true;

            if (notifyDataError)
                this.ClearAllErrors();

            if (string.IsNullOrEmpty(this.Id))
            {
                isValid = false;

                if (notifyDataError)
                    this.SetError("Id", "ID is required");
            }

            if (string.IsNullOrEmpty(this.Name))
            {
                isValid = false;

                if (notifyDataError)
                    this.SetError("Name", "Please specify a name");
            }

            if (string.IsNullOrEmpty(this.Email))
            {
                isValid = false;

                if (notifyDataError)
                    this.SetError("Email", "Please specify an email address");
            }
            else
            {
                if (notifyDataError)
                {
                    if (!Regex.IsMatch(this._email, Contact.EmailPattern))
                        this.SetError("Email", "Invalid email address");
                }
            }

            if (string.IsNullOrEmpty(this.Phone))
            {
                isValid = false;

                if (notifyDataError)
                    this.SetError("Number", "Please specify a phone number");
            }

            return isValid;
        }

        public void SetPhoto(string uri)
        {
            this.Photo = new Uri("/DragDropUXListBox;component/Assets/Images/" + uri + ".jpg", UriKind.RelativeOrAbsolute);
        }

        public void SetPhoto(Uri uri)
        {
            this.Photo = uri;
        }

        #endregion

    }
}

Contact.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:DragDropUXListBox.ViewModels"
        mc:Ignorable="d"
        x:Class="DragDropUXListBox.Views.Contact" 
        Title="Contact Page"
        d:DesignWidth="640" d:DesignHeight="480">

    <Intersoft:UXPage.Resources>
        <ViewModels:ContactViewModel x:Key="ContactsData"/>
    </Intersoft:UXPage.Resources>
    
    <Grid x:Name="LayoutRoot">
        <Intersoft:DockPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Intersoft:DockPanel FillChildMode="Custom" Width="270" Margin="4">
                <Intersoft:StylishLabel Content="Available Personnel" Intersoft:DockPanel.Dock="Top" HorizontalContentAlignment="Left"/>
                <Intersoft:UXSeparator Intersoft:DockPanel.Dock="Top"/>
                <Grid Margin="12" DataContext="{StaticResource ContactsData}" Intersoft:DockPanel.IsFillElement="True">
                    <Intersoft:UXListBox Name="uXListBox1" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" SelectedValuePath="Id" ItemsSource="{Binding ContactsData}" IsTextSearchEnabled="True" DisplayMemberPath="Name" ImageMemberPath="Photo" />
                </Grid>
            </Intersoft:DockPanel>
            <Intersoft:DockPanel FillChildMode="Custom" Width="270" Margin="4">
                <Intersoft:StylishLabel Content="Out-Sourced Personnel" Intersoft:DockPanel.Dock="Top" HorizontalContentAlignment="Left"/>
                <Intersoft:UXSeparator Intersoft:DockPanel.Dock="Top"/>
                <Grid Margin="12" DataContext="{StaticResource ContactsData}" Intersoft:DockPanel.IsFillElement="True">
                    <Intersoft:UXListBox Name="uXListBox2" Height="300" AllowDropItem="True" AllowMoveItem="True" AllowRemoveItem="True" HorizontalAlignment="Stretch" ItemContentType="ContentAndImage" ItemImageHeight="64" ItemImageWidth="64" SelectedValuePath="Id" ItemsSource="{Binding OutsourceData}" IsTextSearchEnabled="True" DisplayMemberPath="Name" ImageMemberPath="Photo" />
                </Grid>
            </Intersoft:DockPanel>
        </Intersoft:DockPanel>
    </Grid>
</Intersoft:UXPage>

ContactViewModel.cs

C#
Copy Code
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Intersoft.Client.Framework.Input;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Resources;
using System.Xml.Linq;
using DragDropUXListBox.Models;

namespace DragDropUXListBox.ViewModels
{
    public class ContactViewModel : ViewModelBase
    {
        // Fields
        private Contact _selectedItem = null;

        // Views
        public ObservableCollection<Contact> Contacts { get; set; }
        public ObservableCollection<Contact> ContactsData { get; set; }
        public ObservableCollection<Contact> OutsourceData { get; set; }

        public string ContactsCount
        {
            get
            {
                if (this.Contacts.Count == 0)
                    return "No contacts";
                else if (this.Contacts.Count == 1)
                    return "1 contact";
                else
                    return this.Contacts.Count + " contacts";
            }
        }

        // Selection, View States
        public Contact SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    _selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                    InvalidateCommands();
                }
            }
        }

        public ContactViewModel()
        {
            this.LoadContacts();
        }

        private void LoadContacts()
        {
            // loads contact data from xml file
            StreamResourceInfo resource = System.Windows.Application.GetResourceStream(
                    new Uri("DragDropUXListBox;component/Assets/Data/ContactDataSource.xml", UriKind.Relative));

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

            var contacts = from x in doc.Descendants("Customer")
                           select new Contact(x);

            this.Contacts = new ObservableCollection<Contact>();
            this.ContactsData = new ObservableCollection<Contact>();
            this.OutsourceData = new ObservableCollection<Contact>();

            foreach (Contact contact in contacts)
            {
                contact.SetPhoto(this.Contacts.Count.ToString());

                this.Contacts.Add(contact);
                                this.ContactsData.Add(contact);
            }

            resource.Stream.Close();
        }

        protected virtual void InvalidateCommands()
        {
        }
    }
}
See Also

Concepts

Other Resources