TreeView in a ComboBox dropdown using RadControls for Silverlight

Saturday, November 08, 2008 by Valeri Hristov | Comments 6

As far as I can tell from the experience of my colleagues with RadControls for ASP.NET AJAX, one of the common feature requests for RadComboBox and RadTreeView is combining them into one piece. Recently we started to receive similar requests for RadComboBox and RadTreeView for Silverlight. Placing a TreeView in a ComboBox sometimes makes a lot of sense, so I decided to research the best way to do it.
 
The first, the simplest and most obvious way is to place a RadTreeView as content of RadComboBox:

<input:RadComboBox>
 <nav:RadTreeView
 ItemTemplate="{StaticResource ItemTemplate}"
 ItemsSource="{StaticResource ItemsSource}" />
</input:RadComboBox>

This works, but it has one important limitation: RadComboBox cannot display the RadTreeView selected item. The problem is that RadTreeView is actually inside a RadComboBoxItem and RadComboBox displays the content of its items. I think that you could create a special ContentPresenter that will display the SelectedItem property of the inner TreeView, but in addition, you should search for ways to avoid other UI glitches, such as RadComboBoxItem highlight around the whole TreeView.
 
I abandoned this approach and created completely different prototype, that follows a WPF article I found on the Internet several months ago (I am unable to find it again, so if you know it, post a comment here with a link and I will give credit to the author). The idea is to replace the RadComboBox ItemsPresenter with a RadTreeView. To do this, I copied the RadComboBox styles into a separate XAML file, effectively creating a new RadComboBox theme (this is something that I will describe in detail in another article). You can see how it works in the attached application.

To keep snippet below short, I removed most of the code, leaving only the elements that demonstrate the idea:

<!-- NonEditableComboBoxTemplate -->
<ControlTemplate x:Key="NonEditableComboBox" TargetType="input:RadComboBox">
 <Grid Name="MainGrid">
  <ToggleButton x:Name="DropDownButton" />
  <ContentPresenter />
  <Popup x:Name="PART_Popup">
   <ScrollViewer x:Name="PART_ScrollViewer">
    <nav:RadTreeView ItemsSource="{TemplateBinding ItemsSource}"
     ItemTemplate="{TemplateBinding ItemTemplate}"
     ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
     ItemContainerStyle="{TemplateBinding ItemContainerStyle}"
     ItemContainerStyleSelector="{TemplateBinding ItemContainerStyleSelector}"
     SelectedValuePath="{TemplateBinding SelectedValuePath}"
     system:ScrollViewer.HorizontalScrollBarVisibility="Disabled"
     system:ScrollViewer.VerticalScrollBarVisibility="Disabled" />
   </ScrollViewer>
  </Popup>
  <Rectangle x:Name="DisabledVisual" />
 </Grid>
</ControlTemplate>

I bound all data related properties of the RadTreeView with the corresponding properties of RadComboBox. I also disabled the integrated scrollbars of RadTreeView. The only thing left is to synchronize RadComboBox.SelectedItem and RadTreeView.SelectedItem. To do that I created a simple class, containing one attached property:

using Telerik.Windows;
public class ComboBoxExtensions
{
 public static bool GetEnableInnerTreeView(DependencyObject obj)
 {
  return (bool)obj.GetValue(EnableInnerTreeViewProperty);
 }
 public static void SetEnableInnerTreeView(DependencyObject obj, bool value)
 {
  obj.SetValue(EnableInnerTreeViewProperty, value);
 }
 public static readonly DependencyProperty EnableInnerTreeViewProperty =
  DependencyProperty.RegisterAttached("EnableInnerTreeView", typeof(bool), typeof(ComboBoxExtensions),
  new System.Windows.PropertyMetadata(InitializeTreeView));
 private static void InitializeTreeView(DependencyObject d,
    DependencyPropertyChangedEventArgs args)
 {
  RadComboBox combo = d as RadComboBox;
  if (combo != null)
  {
   combo.AddHandler(RadTreeView.SelectionChangedEvent,
    new Telerik.Windows.Controls.SelectionChangedEventHandler(
    delegate(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
    {
     RadTreeView tree = e.OriginalSource as RadTreeView;
     if (tree != null)
     {
      combo.SelectedItem = tree.SelectedItem;
      combo.IsDropDownOpen = false;
     }
    }));
  }
 }
}

When you set the attached property on RadComboBox, ComboBoxExtensions attaches a RoutedEvent handler to the RadTreeView's SelectionChanged event. The handler synchronizes the TreeView and the ComboBox, and closes the ComboBox dropdown when you change the selection in the treeview.

Note that the AddHandler extension method will become available after you add "using Telerik.Windows".

The following code demonstrates the RadComboBox declaration:

<input:RadComboBox 
 telerik:RadControl.Theme="{StaticResource TreeInCombo}"
 SelectedValuePath="Text"
 ItemsSource="{StaticResource ItemsSource}"
 ItemTemplate="{StaticResource ItemTemplate}"
 local:ComboBoxExtensions.EnableInnerTreeView="True" />

For completeness, here is the hierarchical ItemTemplate, applied on RadComboBox:

<telerik:HierarchicalDataTemplate x:Key="ItemTemplate" 
  ItemsSource="{Binding Children}"
  ItemTemplate="{StaticResource SubItem}">
 <TextBlock Text="{Binding Text}" />
</telerik:HierarchicalDataTemplate>

Here is the updated source with the latest RadComboBox styles:

TreeInCombo

I hope this article helps. If you have questions just leave a comment here, or write in the RadComboBox forums.

 

6 Comments

  • Brijesh Patil 13 Jan 2009
    As a developer no one would be interested in the third party controls.

    I do not want to use the third party controls for my requirement, please let me know how is it possible to do with the default silverlight.

    My requirement is I need to display the treeview in the combobox and when item selected in the treeview should be displayed in the ComboBox as a selected item.

    Hope you got my point. Any response for this would be appreciated.

    Regards,
    Brijesh Patil.
  • Valeri Hristov 20 Jan 2009
    I am pretty sure that the same approach will work with the standard TreeView and ComboBox. Of course you might need to slightly modify my example, since our controls are different than the standard controls...
  • Rogério Ferreira 26 Mar 2009
    Hello,

    I think your approach is very interesting! I've downloaded your sample application with the source code and tried to run it with the Telerik Silverlight Q1 2009 controls and always got an System.ExecutionEngineException!

    Could you help me solving this issue?

    Thanks.

    Regards,
    Rogério
  • Matt 13 Apr 2011
    Hello, I have an Idea, since in the combobox you only want to show one item which is a TreeView, why don't you just use the Expander control?



    I don't see anything difference if you only want to show one item using Expander and ComboBox



    for showing more than one item, surely using ComboBox is the better choice...



  • developer using third party controls 11 May 2011
    "As a developer no one would be interested in the third party controls."

    - ignorance is bliss
  • Developer 14 Oct 2011
    I downloaded ... build it.. and ran it.. it threws invalid xaml in all xaml files.

Add comment

  1. Formatting options
       
     
     
     
     
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)