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: