Self-reference hierarchy with Telerik TreeView for Silverlight

Posted by: the telerik blogs, on 26 Aug 2009 | View original | Bookmarked: 0 time(s)

Often we need to display in a TreeView flat, self-referencing data, loaded from a database, that has properties ID and ParentID (or similar) that define the hierarchy. The Telerik TreeView for ASP.NET can automatically bind itself to such data, but our Silverlight TreeView cannot do this out of the box. Fortunately, this limitation can be easily avoided with a simple value converter. There is a little trick, however each data item needs a reference to its parent collection.

Consider the following very simple data object:

public class DataItem : INotifyPropertyChanged
{
    private string text; 
 
 public int ID { get; set; }
    public int ParentID { get; set; }
    public DataItemCollection Owner { get; private set; }
    public string Text
    {
        // Standard INotifyPropertyChanged get/set
    }

    internal void SetOwner(DataItemCollection collection)
    {
        this.Owner = collection;
    }

    // INotifyPropertyChanged implementation goes here
}

 

Those data objects are added into a special DataItemCollection class, that inherits ObservableCollection<T> and overrides SetItem(), InsertItem(), RemoveItem() and ClearItems() methods. In each override we call AdoptItem and DiscardItem, respectively, that set the Owner property of the DataItem class:

public class DataItemCollection : ObservableCollection<DataItem>
{
    protected override void InsertItem(int index, DataItem item)
    {
        this.AdoptItem(item);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        this.DiscardItem(this[index]);
        base.RemoveItem(index);
    }

    protected override void SetItem(int index, DataItem item)
    {
        this.AdoptItem(item);
        base.SetItem(index, item);
    }

    protected override void ClearItems()
    {
        foreach (DataItem item in this)
        {
            this.DiscardItem(item);
        }
        base.ClearItems();
    }

    private void AdoptItem(DataItem item)
    {
        item.SetOwner(this);
    }

    private void DiscardItem(DataItem item)
    {
        item.SetOwner(null);
    }
}

 

Normally when you load your data objects from a service in your application you will have auto-generated partial classes, that are relatively easy to extend. You should add partial classes in your application that extend the auto-generated according my code above.

Now we are ready to data-bind our RadTreeView:

<UserControl.Resources> <local:HierarchyConverter x:Key="HierarchyConverter" /> <telerik:HierarchicalDataTemplate x:Name="ItemTemplate" ItemsSource="{Binding Converter={StaticResource HierarchyConverter}}"> <TextBlock Text="{Binding Text}" /> </telerik:HierarchicalDataTemplate> </UserControl.Resources> <StackPanel x:Name="LayoutRoot"> <telerikNavigation:RadTreeView x:Name="TreeView1" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding Converter={StaticResource HierarchyConverter}}" 
 SelectedValuePath="Text" /> <TextBlock Text="{Binding SelectedValue, ElementName=TreeView1}" /> </StackPanel>

 

There is one non-standard thing: all ItemsSource bindings are made through a ValueConverter. This ValueConverter will create the real hierarchy for us:

public class HierarchyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // We are binding an item
        DataItem item = value as DataItem;
        if (item != null)
        {
            return item.Owner.Where(i => i.ParentID == item.ID);
        }

        // We are binding the treeview
        DataItemCollection items = value as DataItemCollection;
        if (items != null)
        {
            return items.Where(i => i.ParentID == 0);
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

When a DataItem object is passed as value, we are binding a TreeViewItem, so the Convert method will return all DataItem objects from the Owner collection that have ParentID equal to the ID of the passed DataItem. When a DataItemCollection is passed, we are binding the TreeView, so the Convert method will return the root-level DataItem objects, that have ParentID=0. Of course, it is up to you to decide whether you want a single, or separate converters for both cases. I did it like this for simplicity, but if you want, you could split the code in two classes.

 

Here is the sample project:

SelfReferenceHierarchyTreeView.zip

 

Thank you for your time, I hope this article will be of help.

Advertisement
Free Agile Project Management Tool from Telerik
TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.
Category: Silverlight | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 2414 | Hits: 9

Similar Posts

  • Telerik Launches RadControls for Silverlight 3 for Line-of-Business Application Development more
  • Telerik Introduces Free Web Testing Framework for ASP.NET AJAX and Silverlight more
  • Moonlight 1.0 Released, Silverlight script updated – and a Chrome hack more
  • Telerik.Charting in RadControls for ASP.NET AJAX Q3 2008 more
  • Silverlight TreeView Load on Demand more
  • Silverlight 2 Resources more
  • "Silverlight: Write and Win!" Contest more
  • Editing Telerik's Silverlight Controls in Expression Blend more
  • Visual Studio 2008 Intellisense and Telerik.Charting more
  • Optimizing the load size of Telerik Silverlight controls more

News Categories

.NET | Agile | Ajax | Architecture | ASP.NET | BizTalk | C# | Certification | Data | DataGrid | DataSet | Debugger | DotNetNuke | Events | GridView | IIS | Indigo | JavaScript | Mobile | Mono | Patterns and Practices | Performance | Podcast | Refactor | Regex | Security | Sharepoint | Silverlight | Smart Client Applications | Software | SQL | VB.NET | Visual Studio | W3 | WCF | WinFx | WPF | WSE | XAML | XLinq | XML | XSD