RadControls for WPF

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 )
{
    // Get the clicked context menu item
    RadMenuItem menuItem = ( ( RadRoutedEventArgs )args ).OriginalSource as RadMenuItem;
    // Find the tree item that is associated with the clicked context menu item
    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)
    ' Get the clicked context menu item
    Dim menuItem As RadMenuItem = TryCast(DirectCast(args, RadRoutedEventArgs).OriginalSource, RadMenuItem)

    ' Find the tree item that is associated with the clicked context menu item
    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 Function

Here is the final result:

See Also