Telerik RadControls provide a very powerful ContextMenu control, that supports right click, modifier keys and that can be easily attached to any visual element. In this article you will see how to attach RadContextMenu to a data-bound RadTreeView and perform actions on the clicked treeview items, depending on the selection in the context menu.
Here you can see how the end result will look like:
For the purpose of this tutorial will be used the following TreeView declaration:
CopyXAML
<UserControl.Resources>
<example:RadTreeViewSampleData x:Key="DataSource"/>
<DataTemplate x:Key="Team">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key="Division" ItemTemplate="{StaticResource Team}"
ItemsSource="{Binding Teams}">
<TextBlock Text="{Binding Name}" />
</telerik:HierarchicalDataTemplate>
<telerik:HierarchicalDataTemplate x:Key="League" ItemTemplate="{StaticResource Division}"
ItemsSource="{Binding Divisions}">
<TextBlock Text="{Binding Name}"/>
</telerik:HierarchicalDataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<telerik:RadTreeView x:Name="radTreeView"
ItemsSource="{Binding Source={StaticResource DataSource}, Path=LeaguesDataSource}"
ItemTemplate="{StaticResource League}" />
</Grid>
For more information about setting the ItemsSource property and data binding read the topic about Binding to Object.
Having the above declaration, you may want to add a context menu only on the items of type "League". Then you will need to update your LeagueHierarchicalDataTemplate:
CopyXAML
<telerik:HierarchicalDataTemplate x:Key="League"
ItemTemplate="{StaticResource Division}"
ItemsSource="{Binding Divisions}">
<TextBlock Text="{Binding Name}">
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu>
<telerik:RadMenuItem Header="New Child" />
<telerik:RadMenuItem Header="New Sibling" />
<telerik:RadMenuItem Header="Delete" />
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</TextBlock>
</telerik:HierarchicalDataTemplate>
To add a handler for the Click event of the context menu, add the following line in the user control constructor:
CopyC#
this.radTreeView.AddHandler( RadMenuItem.ClickEvent,
new RoutedEventHandler( OnContextMenuClick ) );
CopyVB.NET
Me.radTreeView.[AddHandler](RadMenuItem.ClickEvent, New RoutedEventHandler(AddressOf OnContextMenuClick))
Note |
|---|
The AddHandler() extension method is defined in the Telerik.Windows namespace. You should add “using Telerik.Windows;” on top of your code behind if you don’t already have it.
|
The OnContextMenuClick() method finds the clicked RadTreeViewItem and performs the selected action:
CopyC#
private void OnContextMenuClick( object sender, RoutedEventArgs args )
{
RadMenuItem menuItem = ( ( RadRoutedEventArgs )args ).OriginalSource as RadMenuItem;
RadTreeViewItem treeViewItem = FindParentOfType<RadTreeViewItem>( menuItem );
League league = treeViewItem.Item as League;
Telerik.Windows.Controls.ItemsControl parentItemsControl =
( Telerik.Windows.Controls.ItemsControl )treeViewItem.ParentItem ??
treeViewItem.ParentTreeView;
string header = menuItem.Header as string;
switch ( header )
{
case "New Child":
league.Divisions.Add( new Division( "NewDivision", null ) );
break;
case "New Sibling":
( parentItemsControl.ItemsSource as ObservableCollection<League> ).Add( new League( "New League", null ) );
break;
case "Delete":
( parentItemsControl.ItemsSource as ObservableCollection<League> ).Remove( league );
break;
}
}
CopyVB.NET
Private Sub OnContextMenuClick(ByVal sender As Object, ByVal args As RoutedEventArgs)
Dim menuItem As RadMenuItem = TryCast(DirectCast(args, RadRoutedEventArgs).OriginalSource, RadMenuItem)
Dim treeViewItem As RadTreeViewItem = FindParentOfType(Of RadTreeViewItem)(menuItem)
Dim league As League = TryCast(treeViewItem.Item, League)
Dim parentItemsControl As Telerik.Windows.Controls.ItemsControl = If(DirectCast(treeViewItem.ParentItem, Telerik.Windows.Controls.ItemsControl), treeViewItem.ParentTreeView)
Dim header As String = TryCast(menuItem.Header, String)
Select Case header
Case "New Child"
league.Divisions.Add(New Division("NewDivision", Nothing))
Exit Select
Case "New Sibling"
TryCast(parentItemsControl.ItemsSource, ObservableCollection(Of League)).Add(New League("New League", Nothing))
Exit Select
Case "Delete"
TryCast(parentItemsControl.ItemsSource, ObservableCollection(Of League)).Remove(league)
Exit Select
End Select
End Sub
The final element is the FindParentOfType<T>() method, which makes possible finding the RadTreeViewItem that is associated with a given RadMenuItem:
CopyC#
private static T FindParentOfType<T>( UIElement element ) where T : UIElement
{
if ( element == null )
return null;
DependencyObject parent =
Telerik.Windows.RoutedEvent.GetLogicalParent( element ) ??
VisualTreeHelper.GetParent( element );
while ( ( parent != null ) && !( parent is T ) )
{
parent =
Telerik.Windows.RoutedEvent.GetLogicalParent( parent ) ??
VisualTreeHelper.GetParent( parent );
}
return ( T )parent;
}
CopyVB.NET
Private Shared Function FindParentOfType(Of T As UIElement)(ByVal element As UIElement) As T
If element Is Nothing Then
Return Nothing
End If
Dim parent As DependencyObject = If(Telerik.Windows.RoutedEvent.GetLogicalParent(element), VisualTreeHelper.GetParent(element))
While (parent IsNot Nothing) AndAlso Not (TypeOf parent Is T)
parent = If(Telerik.Windows.RoutedEvent.GetLogicalParent(parent), VisualTreeHelper.GetParent(parent))
End While
Return DirectCast(parent, T)
End FunctionHere is the final result:
See Also