Part one: Moving a child element from one parent to another

1. Problem

 

 

The purpose of this post is to show one possible way to solve the following scenario.

Having a Silverlight RadTreeView that loads its items from a database via WCF RIA services, we want to update the database immediately after a drag and drop operation has been performed within the RadTreeView.

The drag and drop operation in this post will be moving a child element from one parent to another. Reordering items will be shown in a future post.

2.Design

 

 

We will be using the MVVM Design Pattern. Let’s take a close look at its parts:

2.1 The Model

An ADO.NET Entity Data Model that will connect the Silverlight Web Application to the database. We will use the Categories and Products table from the well-known Northwind Database.

ado

DB

2.2. The view

The view answers the question: How will the data be presented? The hierarchical structure of RadTreeView will be described via HierarchicalDataTemplates.

<Grid.Resources>
            <telerik:HierarchicalDataTemplate x:Key="ProductLeveltemplate">
                <TextBlock FontSize="14" 
                           FontWeight="Bold"
                           Foreground="DeepSkyBlue"
                           Text="{Binding Name}" />
            </telerik:HierarchicalDataTemplate>
  
            <telerik:HierarchicalDataTemplate x:Key="CategoryLevelTemplate" 
                                              ItemsSource="{Binding Products}"
                                              ItemTemplate="{StaticResource ProductLeveltemplate}">
                <TextBlock FontSize="16" 
                           FontWeight="Bold"
                           Foreground="MediumBlue"
                           Text="{Binding Name}" />
            </telerik:HierarchicalDataTemplate>
        </Grid.Resources>
  
        <telerik:RadTreeView x:Name="treeView" 
                             HorizontalAlignment="Center"
                             IsDragDropEnabled="True"
                             ItemsSource="{Binding Categories}"
                             ItemTemplate="{StaticResource CategoryLevelTemplate}" />
    </Grid>

2.3. The ViewModels

  • ProductViewModel: wraps a Product and exposes its Name property
  • CategoryViewModel: wraps a Category and exposes its Name and collection of ProductViewModels(a collection of Products for the category)
  • TreeViewViewModel: exposes a collection of CategoryViewModels and will be used as DataContext for the RadTreeView

3.Solution

 

 

 

First we need a Domain Service Class that will manage the C.R.U.D. operations between the client and the database.

dsclass

Then we will create two private domain context fields, one in TreeViewViewModel and one in CategoryViewModel . They will be used for loading the Category and Product collections via Lazy Loading technique as shown below:

public class TreeViewViewModel : ViewModelBase
    {
        private DomainServiceNorthwind context;
  
        private ObservableCollection<CategoryViewModel> categories;
        public ObservableCollection<CategoryViewModel> Categories
        {
            get
            {
                if (categories == null)
                {
                    context = new DomainServiceNorthwind();
                    context.Load<Category>(context.GetCategoriesQuery(), lo =>
                    {
                        categories = new ObservableCollection<CategoryViewModel>(
                            context.Categories.Select(x => new CategoryViewModel(x)));
                        OnPropertyChanged("Categories");
                    }, null);
                }
                return categories;
            }
        }
    }

Now that we’ve set up our ViewModels and bound them to the RadTreeView, we need to set RadTreeView’s IsDragAndDropEnabledProperty to True. Then we need to drag a product from one category and drop it in another. The next time we rebind the tree (reload the Silverlight application) the changes that we have made previously will be reflected. This particular drag and drop operation changes the ItemsSource collections of the RadTreeViewItems which are ObservableCollection<Product>.  ObservableCollection<T> implements the ICollectionChanged interface and therefore gets notified immediately after change- Add, Remove, Replace, Reset operation). The only thing we have to do is to use the NotifyCollectionChangedEventHandler of the Product collection and substitute the old CategoryID of the newly added Product with the new CategoryID of the current Category and submit this change in the database.

void Products_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {       
            if (e.Action == NotifyCollectionChangedAction.Add )
            {
                ProductViewModel product = e.NewItems[0] as ProductViewModel;
                var oldCatId = product.ProductModel.CategoryID;
                if (oldCatId != null && oldCatId != this.categoryModel.CategoryID)
                {
                    Product productFFromBase = context.Products.
                        Where(x => x.ProductID == product.ProductModel.ProductID).FirstOrDefault();
                    productFFromBase.CategoryID = this.categoryModel.CategoryID;
                    context.SubmitChanges();
                }
            }
        }

Finally, we have to validate our drag and drop behavior. This includes:

  • Disabling the ability to drop Product in RadTreeView’s root level
  • Disabling the Drag and Drop feature on Categories
  • Setting the DragCue`s visibility on specific cases

We use the drag and drop events of both RadDragAndDropManager and RadTreeView for this purpose.

4.Result

 

 

Now let’s test our application. We’ll drag a product from “Meat / Poultry” and drop it in the “Produce” category:

base3

Then we reload the Silverlight application and get the desired result: the “Ikura” is in the “Produce” Category:

base4

 ===================================================================================

Advantages of this approach 

 

  •        MVVM
  •        Lazy Loading
  •        DragCue is automatically generated in most cases 

Disadvantages 

 

  •        More code due to the ViewModels used, more maintenance needed 

In the next posts we'll go through other drag and drop operations such as reordering of items and we will show approaches that do not use MVVM pattern and work directly with the database.The full source code from this post could be found in the following archive: 

TreeViewDNDWithRia  

Thank you for your interest in RadTreeView for Silverlight !


About the Author

Valio Stoychev

Valentin Stoychev (@ValioStoychev) for long has been part of Telerik and worked on almost every UI suite that came out of Telerik. Valio now works as a Product Manager and strives to make every customer a successful customer.

 

Comments

Comments are disabled in preview mode.