Aug 21

Written by: Michael Washington
8/21/2011 9:35 PM  RssIcon

image

Note: Also see Using The Sheel Shah Many-To-Many Control for an example of a control that allows you to associate a tree with another entity.

Hierarchical data is unusually used to display data in a tree. The data typically is in a single table that is self-referencing, meaning it has one property that points to other records in the same table. This is how it is able to track the parent-child relationship between records. A Tree Control is usually used to visualize hierarchical data.

Karol Zadora-Przylecki (Microsoft) created an example, and included important code required by LightSwitch when using a Silverlight Tree Control. You can see the original post here: http://social.msdn.microsoft.com/Forums/en-US/lsextensibility/thread/bcdaa86f-459a-47d3-853a-3c5e56eb088a. In this article, we will follow the concepts outlined by that post.

Note: If you are new to LightSwitch, it is suggested that you start here: Online Ordering System (An End-To-End LightSwitch Example)

 

The Sample Application

image

First we create a Entity (table) with the structure according to the image above.

  • CategoryName – The name of the node
  • IsSelected – We will have a check box in the Tree Control that will be bound to this
  • IsRootNode – The query that we will use to bind the collection to the Tree Control, will need to only bind to records that have this set to True

 

image

Next, we click the Relationship button so we can make this Entity self-referencing.

 

image

We then perform the following steps:

  1. Select Category for Name in the To column (this points the Entity to itself)
  2. Select Zero or one for Multiplicity in the From column (this allows some records to not have a self-referencing relationship)
  3. Select Many for Multiplicity in the To column (this indicates that one Parent record can be related to many child records)
  4. Enter ParentCategory for Navigation Property in the To column (this provides a name for the relationship that is being created)
  5. Click OK

 

image

We see that a Categories collection has been added to the Entity, and self-referencing relationship has been created between it and the ParentCategory property that has also been added to the Entity.

 

image

We then create a Editable Grid Screen.

 

image

We run the application and enter some sample data.

 

Create The Collection For The Tree Control To Bind To

image

We cannot simply bind the Tree Control to the Categories collection because it would show all the nodes in the “root” of the Tree Control.

You actually want the Tree Control to bind only to the "root nodes" (nodes that do not have a parent). The child nodes (of the root nodes) will then be displayed as the Tree Control recursively walks the collection.

This is why we added a Bool property to the collection (IsRootNode). We will add a new query and a filter to only return root nodes. We will bind the Tree Control to this collection.

Click the Add Data Item button.

 

image

Select the Categories collection and name it CategoriesTree.

 

image

Edit the query for the CategoriesTree collection.

 

image

Edit the query to only show nodes that have IsRootNode set to True.

 

image

Click the Back button to return to the main screen.

 

Create The Silverlight Project

image

Add a new Project.

 

image

Create a Silverlight Class Library. Call it SilverlightProject.

 

image

Select Silverlight 4.

 

image

Delete the Class1.cs file that is created.

 

image

In the SilverlightProject, add references to:

Microsoft.LightSwitch,
Microsoft.LightSwitch.Client
Microsoft.LightSwitch.Base.Client

(they are all located under (VS installation directory)\Common7\IDE\LightSwitch\1.0\Client)

Also add a Reference to:

System.Windows.Controls

 

image

Add a class called EntityCollectionValueConverter.cs with the following code:

 

using System;
using System.Windows.Data;
using Microsoft.LightSwitch;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Collections.Generic;
namespace SilverlightProject
{
    // By: Karol Zadora-Przylecki (Microsoft)
    // From: http://bit.ly/oNTsJo
    // Ensures that an entity collection is loaded before accessed by UI thread.
    // The binding should use the whole entity object as data binding context
    public class EntityCollectionValueConverter : IValueConverter
    {
        public object Convert(object value, 
            Type targetType, 
            object parameter, 
            System.Globalization.CultureInfo culture)
        {
            string strErrorMessage
                = "Converter parameter should be set to the property name that will serve as source of data";
                
            IEntityObject entity = value as IEntityObject;
            if (entity == null) 
                throw new ArgumentException("The converter should be using an entity object");
            string sourcePropertyName = parameter as string;
            if (string.IsNullOrWhiteSpace(sourcePropertyName)) 
                throw new ArgumentException(strErrorMessage);
            
            // Enumerate the source property using logic dispatcher 
            // and prepare the collection of entities that the control will bind to
            var entities = new ObservableCollection<IEntityObject>();
            var temporaryEntites = new List<IEntityObject>();
            entity.Details.Dispatcher.BeginInvoke(delegate
            {
                IEntityCollection eCollection = 
                    entity.Details.Properties[sourcePropertyName].Value as IEntityCollection;
                if (eCollection == null)
                {
                    Debug.Assert(false, "The property " + sourcePropertyName + " is not an entity collection");
                    return;
                }
                // Now we are on the logic thread. We cannot just stuff the observable collection
                // with entities because the collection will immediately raise Changed events
                // and this will result in invalid cross-thread access. So we'll use a temporary collection
                // and copy the entites again on the UI thread
                foreach (IEntityObject e in eCollection)
                {
                    temporaryEntites.Add(e);
                }
                Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(delegate
                {
                    // I wish ObservableCollection had an AddRange() method...
                    foreach (IEntityObject e in temporaryEntites)
                    {
                        entities.Add(e);
                    }
                });
            });
            return entities;
        }
        public object ConvertBack(object value, 
            Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

 

This code was created by Karol Zadora-Przylecki of Microsoft, and it is key to making the Tree Control work with LightSwitch.

You can find out more about how the Silverlight Tree Control works at this link: http://blogs.silverlight.net/blogs/justinangel/archive/2009/05/19/silverlight-treeview-advanced-scenarios-treeviewextended.aspx.

You can find more about the challenges Karol’s code solves in the post at: http://social.msdn.microsoft.com/Forums/en-US/lsextensibility/thread/bcdaa86f-459a-47d3-853a-3c5e56eb088a/.

 

image

Right-click on the SilverlightProject and add New Item…

 

image

Create a Silverlight User Control. Call it SilverlightTreeControl.xaml.

 

Use the the following code for the SilverlightTreeControl.xaml file:

 
<UserControl x:Class="SilverlightProject.SilverlightTreeControl"
    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:local="clr-namespace:SilverlightProject"    
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <UserControl.Resources>
        <local:EntityCollectionValueConverter x:Key="EntityCollectionValueConverter" />
    </UserControl.Resources>
    
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Orientation="Horizontal">
            <sdk:TreeView Name="treeViewControl" ItemsSource="{Binding Screen.CategoriesTree}">
                <sdk:TreeView.ItemTemplate>
                    
                    <sdk:HierarchicalDataTemplate 
                            ItemsSource="{Binding 
                        Converter={StaticResource EntityCollectionValueConverter}, 
                        ConverterParameter=Categories}">
                        
                        <StackPanel Orientation="Horizontal">                            
                           
                            <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}"/>
                            
                            <TextBlock Text="{Binding Path=CategoryName, Mode=TwoWay}" 
                                       Margin="5,0" Width="74" />
                        </StackPanel>
                    </sdk:HierarchicalDataTemplate>
                </sdk:TreeView.ItemTemplate>
            </sdk:TreeView>
        </StackPanel>
    </Grid>
</UserControl>

 

Basically this just binds the Tree Control to: Screen.CategoriesTree and implements Karol’s ValueConverter.

Note: binding to Silverlight Controls in LightSwitch is explained in detail in the book:

Creating Visual Studio LightSwitch Custom Controls (Beginner to Intermediate)

 

image

Build the Silverlight project.

 

Add The Control To LightSwitch

image

In the LightSwitch screen designer, change the layout to Columns Layout.

 

image

Add a new Custom Control.

 

image

Click the Add Reference Button.

 

image

Create a Project reference to the SilverlightProject project.

 

image

You will now be able to select the Custom Control you created.

Leave Screen in the Path Text Box, because we programmed the binding in the Tree Control to use the data coming from Screen.

Click OK.

 

image

Drag the Custom Control above the Data Grid in the object tree.

 

image

Set the Properties for the control according to the image above.

 

image

When you run the project the Tree Control will display.

 

Update: Refresh the Tree Automatically

image

In the LightSwitch Screen designer, you can wire up an event on the Data Grid to detect when a record is saved.

Then use the following code to refresh the collection the Tree Control is bound to:

 

    public partial class EditableCategoriesGrid
    {
        partial void EditableCategoriesGrid_Saved()
        {
            CategoriesTree.Refresh();
        }
    }

 

Special Thanks

A special thanks to Karol Zadora-Przylecki because otherwise this article would not be possible.

 

Download Code

The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

21 comment(s) so far...


Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

This is great, Michael. I followed your instructions above to the letter and was able to duplicate the tree! After a couple weeks of getting nowhere it is a real pleasure to finally succeed (albiet with plenty of help from you, Karol, and others). I bought your ebook on using SL controls in LS as soon as it came out several weeks ago and it has helprf a great deal also. Thanks also for the references to further reading and background. I will definite avail myself of that info.

Thanks, again,
Ed

By edmiller on   8/22/2011 6:53 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@edmiller - I am glad it worked for you. I appreciate the feedback.

By Michael Washington on   8/22/2011 7:38 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Hi Michael,

great writeup of the pieces that were hidden in the MSDN forums. However, I have one problem to apply this to my own project. My data structure is a bit different and the tree component I use offers a slightly easier mechanism to use id and parent id. Thus, I simply need to hand a list of the entities to the component. I do not need the parameter of the binding for the converter.

Big issue though: Lightswitch hands me a VisualCollection. I am unable to get from there to an EntityCollection. What am I missing?

By Holger Flick on   8/22/2011 9:44 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@ Holger Flick - That is an Entity collection I am using in my example. Please make a post in the forums on this site because the comments section of this blog is a horrible place for a technical discussion.

By Michael Washington on   8/22/2011 9:50 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Hi.
This looks to be a great "how to" that I've been looking for but I can't follow it because my install of Lightswitch 2011 doesn't contain the the "Silverlight Class Library". I've spent the last four hours looking in Google for anything; came across some hopeful solutions but none of them panned out. Any idea what I can do to install the Silverlight Class Library?

Lightswitch help/about yields:
Microsoft Visual Studio 2010
Version 10.0.40219.1 SP1Rel
Microsoft .NET Framework
Version 4.0.30319 SP1Rel

Installed Version: LS Standard
Microsoft Visual Basic 2010
Microsoft Visual C# 2010
Microsoft Visual Studio 2010 Team Explorer
Microsoft Visual Studio LightSwitch 2011
Microsoft Package Manager 1.0
Package Manager in Visual Studio

all installed via "visual web" (http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-web-developer-express)... that should have installed the templates but I guess not. Help?

Thank you.

By JustStarting on   8/25/2011 1:54 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@JustStarting you need Visual Studio Pro (or higher) to run this sample

By Michael Washington on   8/25/2011 1:55 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Great functionality, but how do i connect the selected item in the tree to the same row in the grid?

By Rients Hofstede on   9/6/2011 9:28 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@Rients Hofstede - When you run my sample it should do this automatically.

By Michael Washington on   9/15/2011 8:49 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Great work

but
connect the selected item in the tree to the same row in the grid?
didn't work very well I hope I know how to improve it

By emad on   9/26/2011 10:35 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@emad - The check boxes will be correct, but the selected node is not implemented in this example to keep it simple.

By Michael Washington on   9/26/2011 10:36 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Hi Micheal,
thanks for your work, but I've a problem.
I'm trying to adapt you tutorial to my application, but I experience an error that I can't solve.

So, in order to learn, I tryed to replicate your tutorial. And I've the same problem!

I wrote this in forum, this is the link:
http://lightswitchhelpwebsite.com/Forum/tabid/63/aft/281/Default.aspx

Please, could you help me?
Thanks in advance

By vbalox on   9/27/2011 11:55 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Hi Michael,
This is great for diplaying data from within Categories but i would also like to display related products in a grid below the tree relative to the highlighted (probably clicked) node within the tree. ie similar to clicking a row in the Categories grid. How do you make the Tree select a row in the Categories grid?

I appreciate this is similar to earlier posts but I hope by adding my request you'll consider extending this very useful control or else provide some help.

Thanks in advance

By phrezil on   10/7/2011 8:54 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@phrezil - Sheel Shah will release a control that will do as you require. I don't know when, but I have tested it and it does work.

By Michael Washington on   10/7/2011 8:56 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

Great post!

I have created the control without the IsSelected CheckBox (and column) so I have a treeview with the option to click nodes.

My plan is to put the control in my "... Set List Details" screen, so by clicking a node, details of the selected node will apear on the right and so adding nodes will be available on top.

Any directions on how can that be accomplished?

Thanks!

By Doron Goldberg on   11/8/2011 5:28 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@Doron Goldberg - Please post technical questions to the forums, thanks.

By Michael Washington on   11/8/2011 5:28 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

I am new to lightswitch. I am trying to follow what you have done. When I try to add a new project to add the silverlight project, there is no 'add' option in the File menu. Do you know what is going on here?

Thank you

Shannon

By Shannon on   4/2/2012 1:40 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@Shannon - You have to have the full version of Visual Studio

By Michael Washington on   4/2/2012 2:35 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

I wonder if there is a version of the Code for vb.net?
I tried to convert the class to vb.net but I can not.
could someone help me?
Thank you.

By Geraldo on   10/4/2012 12:58 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch - SelectedItem

Has anyone solved the selecteditem side of the tree control?

I have this working perfectly with my self-referencing tree data grid but I want the selected item to update every time I click in the tree. I assume I am not the first person to want this functionality. In fact there is a comment in the chain requesting it. Has anyone ever tackled the problem?

To be clear, when I click an item in the tree, I want the selecteditem in the grid to be updated to that item. Seems like it should be pretty straight forward (famous last words).

Thank you in advance.

By eWorthy on   11/2/2012 2:50 PM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

What if I want to make this but with stored procedure instead of table? Stored procedures can't have navigation properties that point to themselves, I think?

By svetoslav80 on   12/12/2012 10:18 AM
Gravatar

Re: Tree Control: Hierarchical Data with LightSwitch

@svetoslav80 - You can have a WCF RIA Service consume the stored procedure and it may work. I have no examples, however.

By Michael Washington on   12/12/2012 10:45 AM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation