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