TreeView in a ComboBox dropdown using RadControls for Silverlight

Posted by: the telerik blogs, on 08 Nov 2008 | View original | Bookmarked: 0 time(s)

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>

However, 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 only 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 two RadComboBox control templates into a separate XAML file, effectively creating a new RadComboBox skin (this is something that I will describe in detail in another article). You can see how it worksin the attached source. To keep this article 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 handlerto 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. 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:

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

You may ask "Why not bind the SelectedItem properties of the two controls?". The answer is - RadTreeView's SelectedItem property is read-only and Silverlight does not provide the needed instruments (Triggers) to bind a read-only property. "Why SelectedItem is read-only?" you may ask - the answer is "Because RadTreeView is hierarchical control".

Here is the source:

TreeInCombo

I hope this article helps. Let me know if you have questions, you know how to find me :)

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: Data | Other Posts: View all posts by this blogger | Report as irrelevant | View bloggers stats | Views: 5298 | Hits: 38

Similar Posts

  • Moonlight 1.0 Released, Silverlight script updated – and a Chrome hack more
  • "Silverlight: Write and Win!" Contest more
  • Beta version of Rad Controls for Silverlight 2 available more
  • RadControls for Silverlight 2 CTP2 release more
  • TreeView and Web Services more
  • Migrating Web.UI client-side code to AJAX Library syntax more
  • ASP.NET: TreeView selection - SelectAction tip/trick 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