Attaching a ContextMenu on a TreeView with RadControls for Silverlight

by XAML Team | Comments 7

Telerik RadControls for Silverlight 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 I will show 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. For simplicity, here I will use a treeview, bound to a static collection, but it can be easily extended to load its items from a web service:

<UserControl x:Class="ContextMenuInTreeView.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ContextMenuInTreeView" xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" xmlns:telerikNavigation="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation"> <UserControl.Resources> <local:DataViewModel x:Key="ViewModel" /> <telerik:HierarchicalDataTemplate x:Key="TreeViewItemTemplate" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Text}"> <telerikNavigation:RadContextMenu.ContextMenu> <telerikNavigation:RadContextMenu> <telerikNavigation:RadMenuItem Header="New Child" /> <telerikNavigation:RadMenuItem Header="New Sibling" /> <telerikNavigation:RadMenuItem Header="Delete" /> </telerikNavigation:RadContextMenu> </telerikNavigation:RadContextMenu.ContextMenu> </TextBlock> </telerik:HierarchicalDataTemplate> </UserControl.Resources> <StackPanel Background="White" DataContext="{StaticResource ViewModel}"> <TextBlock Text="Right-click the tree view to show a context menu" /> <telerikNavigation:RadTreeView x:Name="TreeView" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource TreeViewItemTemplate}" /> </StackPanel> </UserControl>

 

The DataViewModel class is the main data storage, that creates the TreeView data items. Its Items property is of type DataItemCollection and contains DataItem objects:

[ContentProperty("Children")]
public class DataItem
{
    public DataItem()
    {
        this.Children = new DataItemCollection();
    }

    public string Text { get; set; }

    public DataItemCollection Children { get; private set; }
}

public class DataItemCollection : ObservableCollection<DataItem>
{
}

 

To enable the right clicking you should make the Silverlight plugin windowless. To do that open the ASPX page where the Silverlight is declared and add attribute windowless=”true”:

<asp:Silverlight ID="Xaml1" runat="server" 
 Windowless="true" Source="~/ClientBin/ContextMenuInTreeView.xap" 
 MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />

 

If your Silverlight plugin is declared as an Object element, add the following param tag:

<object ...>
  <param name="windowless" value="true"/>
  ...
</object>

 

The final result should look like this:

ContextMenuInTreeView

 

To add a handler for the Click event of the context menu, add the following line in the page constructor:

using Telerik.Windows;
public partial class Page : System.Windows.Controls.UserControl
{
    public Page()
    {
        InitializeComponent();

        this.TreeView.AddHandler(RadMenuItem.ClickEvent, 
            new RoutedEventHandler(OnContextMenuClick));
    }

    ...
}

Note that 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:

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);

    DataItem dataItem = treeViewItem.Item as DataItem;

    ItemsControl parentItemsControl = 
        (ItemsControl)treeViewItem.ParentItem ?? 
        treeViewItem.ParentTreeView;

    string header = menuItem.Header as string;
    switch (header)
    {
        case "New Child":
            dataItem.Children.Add(new DataItem() { Text = "New Item" });
            break;

        case "New Sibling":
            (parentItemsControl.ItemsSource as DataItemCollection).Add(
 new DataItem() { Text = "New Item" });
            break;

        case "Delete":
            (parentItemsControl.ItemsSource as DataItemCollection).Remove(dataItem);
            break;
    }
}

The final element is the FindParentOfType<T>() method, which makes possible finding the RadTreeViewItem that is associated with a given RadMenuItem:

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;
}

 

The source code of the application can be found here:

Valeri Hristov
Team Lead,
Platform Team

7 Comments

Pete Davies
Hello Valeri,
Many thanks for this blog.
It was ALMOST very useful.
I am not sure why experts never seem to include the one thing that I need the most.
Anyway, I do not wish to complain because I found your explanation very useful as far as it goes.
What would really finish it off and make things brilliant would be an EDIT menu item.
I was wondering if the reason you might have left editing out, is because it is too difficult.
I have been trying for a couple of days now, and have got nowhere.
Anyway, please help if you have time. I would really appreciate it :-)

Regards,

Pete.
Valeri Hristov
Hi Pete,

To edit the RadTreeViewItem you need to modify the OnContextMenuClick method like this:
...
case "Edit": 
    this.Dispatcher.BeginInvoke(() => 
    { 
        treeViewItem.BeginEdit(); 
    }); 
    break;
...

However, there is a small problem - RadTreeView contains a bug that breaks the editing when the control is data bound, which is the reason I did not include this feature in my example. We will try to fix this problem for one of the next updates of RadTreeView.

Thank you for your feedback!

Valeri Hristov
piyush
Hey,

We bought Telerik Silverlight controls last week. we are facing one problem of right click on tree view control. when i select any folder and do right click on it, its working fine but when you select folder and right click on other folder the control perform action on selected folder instead of right click folder..

the telrik demo example of right click on treeView also doing the same. so is there anyway to change the selection of folder on right click ?


kindly waiting for the reply.

thanks,

Piyush Patel
Valeri Hristov
We have a better example, that demonstrates some new API in RadContextMenu:
http://demos.telerik.com/silverlight/#ContextMenu/FirstLook

To select the clicked TreeViewItem when the context menu is displayed, in the ContextMenuOpened method, call:
this.ClickedTreeViewItem.IsSelected = true;
piyush
thanks man,

What i did on the ContextMenuOpened method, call:

treeView.SelectedItem = this.ContextMenu.GetClickedElement<RadTreeViewItem>().Item;

treeView = treeView Control name
ContextMenu = ContextMenu name

thanks,

Piyush
Matt
How do you go about skinning the context menu?
mohammad
Hello
When  my
control is righttoleft,
  Menu is displayed on the right side

Comments

  1.    
      
      
       
  2. (optional, emails won't be shown on public pages)
  3. (optional)
Read more articles by XAML Team - or - read latest articles in Developer Tools