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.
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.
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
First we need a Domain Service Class that will manage the C.R.U.D. operations between the client and the database.
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
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:
We use the drag and drop events of both RadDragAndDropManager and RadTreeView for this purpose.
Now let’s test our application. We’ll drag a product from “Meat / Poultry” and drop it in the “Produce” category:
Then we reload the Silverlight application and get the desired result: the “Ikura” is in the “Produce” Category:
===================================================================================
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:
Thank you for your interest in RadTreeView for Silverlight !
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.