Telerik UI for Silverlight

As the RadMenuItem implements the ICommandSource interface, you are able to use any kind of commands that inherit from the ICommand interface with it. This tutorial will show you how to use the RadContextMenu with RoutedUICommands combined with the MVVM pattern. Two commands are going to be exposed - one for moving an item in a ListBox up and one for moving an item down. The following things will come in focus:

Attaching a RadContextMenu to a ListBox control

Before getting to the commands, you have to prepare the UI on which they will get executed. In this tutorial a ListBox and a RadContextMenu are used.

CopyXAML
<ListBox x:Name="listBox">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu">
        </telerik:RadContextMenu>
    </telerik:RadContextMenu.ContextMenu>
</ListBox>

Having the UI prepared, you have to add some data to it.

Populating the ListBox with data via a ViewModel

As the MVVM pattern should be used, you have to create a ViewModel for your UserControl, which will control its behavior. In it you will store the data which the View is using. Here is the declaration of the ViewModel class. It has a constructor, a method that initializes the items for the ListBox and an Items property, that stores them. Additionally create a SelectedItem property that will hold the selected item of the ListBox.

CopyC#
public class ExampleViewModel : INotifyPropertyChanged
{
    private DataItem selectedItem;
    public ExampleViewModel()
    {
        this.InitItems();
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public ObservableCollection<DataItem> Items
    {
        get;
        set;
    }
    public DataItem SelectedItem
    {
        get
        {
            return this.selectedItem;
        }
        set
        {
            if ( this.selectedItem != value )
            {
                this.selectedItem = value;
                this.OnNotifyPropertyChanged( "SelectedItem" );
            }
        }
    }
    private void OnNotifyPropertyChanged( string propertyName )
    {
        if ( this.PropertyChanged != null )
        {
            this.PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
        }
    }
    private void InitItems()
    {
        ObservableCollection<DataItem> items = new ObservableCollection<DataItem>();
        items.Add( new DataItem( "Item 1" ) );
        items.Add( new DataItem( "Item 2" ) );
        items.Add( new DataItem( "Item 3" ) );
        this.Items = items;
    }
}
CopyVB.NET
Public Class ExampleViewModel
 Implements INotifyPropertyChanged
 Private selectedItem As DataItem
 Public Sub New()
  Me.InitItems()
 End Sub
 Public Event PropertyChanged As PropertyChangedEventHandler
 Public Property Items() As ObservableCollection(Of DataItem)
  Get
  End Get
  Set
  End Set
 End Property
 Public Property SelectedItem() As DataItem
  Get
   Return Me.selectedItem
  End Get
  Set
   If Me.selectedItem <> value Then
    Me.selectedItem = value
    Me.OnNotifyPropertyChanged("SelectedItem")
   End If
  End Set
 End Property
 Private Sub OnNotifyPropertyChanged(propertyName As String)
  If Me.PropertyChanged <> Nothing Then
   Me.PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  End If
 End Sub
 Private Sub InitItems()
  Dim items As New ObservableCollection(Of DataItem)()
  items.Add(New DataItem("Item 1"))
  items.Add(New DataItem("Item 2"))
  items.Add(New DataItem("Item 3"))
  Me.Items = items
 End Sub
End Class

In the constructor of the UserControl you have to create an instance of the ViewModel, store it in a field and pass it as a DataContext of the entire UserControl.

CopyC#
private ExampleViewModel viewModel;
public CommandsSample()
{
    InitializeComponent();
    this.viewModel = new ExampleViewModel();
    this.DataContext = viewModel;
}
CopyVB.NET
Private viewModel As ExampleViewModel
Public Sub New()
 InitializeComponent()
 Me.viewModel = New ExampleViewModel()
 Me.DataContext = viewModel
End Sub

In the XAML you have to set the SelectedItem, the DisplayMemberPath and the ItemsSource properties of the ListBox in order to visualize the data.

CopyXAML
<ListBox x:Name="listBox"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu">
        </telerik:RadContextMenu>
    </telerik:RadContextMenu.ContextMenu>
</ListBox>

Selecting the right-clicked ListBoxItem

Before continuing, there is one more thing to be done. When right-clicking to open the RadContextMenu, the clicked item should get selected, or if no item was clicked, the selection should be removed. This is done by handling the Opened event of the RadContextMenu.

CopyXAML
<ListBox x:Name="listBox"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu"
                                          Opened="RadContextMenu_Opened">
        </telerik:RadContextMenu>
    </telerik:RadContextMenu.ContextMenu>
</ListBox>
CopyC#
private void RadContextMenu_Opened( object sender, RoutedEventArgs e )
{
    System.Windows.Controls.ListBoxItem item = this.radContextMenu.GetClickedElement<System.Windows.Controls.ListBoxItem>();
    if ( item != null )
    {
        this.listBox.SelectedItem = item.DataContext;
    }
    else
    {
        this.listBox.SelectedItem = null;
    }
}
CopyVB.NET
Private Sub RadContextMenu_Opened(sender As Object, e As RoutedEventArgs)
 Dim item As System.Windows.Controls.ListBoxItem = Me.radContextMenu.GetClickedElement(Of System.Windows.Controls.ListBoxItem)()
 If item <> Nothing Then
  Me.listBox.SelectedItem = item.DataContext
 Else
  Me.listBox.SelectedItem = Nothing
 End If
End Sub

Preparing the RoutedUICommands

The next step is to create your commands. They will be host by the ViewModel.

CopyC#
public RoutedUICommand MoveUpCommand
{
    get;
    private set;
}
public RoutedUICommand MoveDownCommand
{
    get;
    private set;
}
CopyVB.NET
Public Property MoveUpCommand() As RoutedUICommand
 Get
 End Get
 Private Set
 End Set
End Property
Public Property MoveDownCommand() As RoutedUICommand
 Get
 End Get
 Private Set
 End Set
End Property

Initialize them in the constructor of the ViewModel:

CopyC#
public ExampleViewModel()
{
    this.MoveUpCommand = new RoutedUICommand( "Move Up", "MoveUp", typeof( ExampleViewModel ) );
    this.MoveDownCommand = new RoutedUICommand( "Move Down", "MoveDown", typeof( ExampleViewModel ) );
    this.InitItems();
}
CopyVB.NET
Public Sub New()
 Me.MoveUpCommand = New RoutedUICommand("Move Up", "MoveUp", GetType(ExampleViewModel))
 Me.MoveDownCommand = New RoutedUICommand("Move Down", "MoveDown", GetType(ExampleViewModel))
 Me.InitItems()
End Sub

Bind them in the View.

CopyXAML
<ListBox x:Name="listBox"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu"
                                          Opened="RadContextMenu_Opened">
            <telerik:RadMenuItem Header="{Binding MoveUpCommand.Text}"
                                           Command="{Binding MoveUpCommand}" />
            <telerik:RadMenuItem Header="{Binding MoveDownCommand.Text}"
                                           Command="{Binding MoveDownCommand}" />
        </telerik:RadContextMenu>
    </telerik:RadContextMenu.ContextMenu>
</ListBox>

You will also need methods that will get called when the command is executed. In the next section is explained how to connect the methods to the command. Here are sample methods for the two commands.

CopyC#
public void MoveUp( object sender, ExecutedRoutedEventArgs e )
{
    if ( this.SelectedItem == null || this.Items.IndexOf( this.SelectedItem as DataItem ) == 0 )
    {
        return;
    }
    DataItem item = this.SelectedItem;
    int index = this.Items.IndexOf( item as DataItem );
    this.Items.Remove( item as DataItem );
    this.Items.Insert( index - 1, item as DataItem );
    this.SelectedItem = item;
}
public void MoveDown( object sender, ExecutedRoutedEventArgs e )
{
    if ( this.SelectedItem == null || this.Items.IndexOf( this.SelectedItem as DataItem ) == this.Items.Count - 1 )
    {
        return;
    }
    DataItem item = this.SelectedItem;
    int index = this.Items.IndexOf( item as DataItem );
    this.Items.Remove( item as DataItem );
    this.Items.Insert( index + 1, item as DataItem );
    this.SelectedItem = item;
}
CopyVB.NET
Public Sub MoveUp(sender As Object, e As ExecutedRoutedEventArgs)
 If Me.SelectedItem = Nothing OrElse Me.Items.IndexOf(TryCast(Me.SelectedItem, DataItem)) = 0 Then
  Return
 End If
 Dim item As DataItem = Me.SelectedItem
 Dim index As Integer = Me.Items.IndexOf(TryCast(item, DataItem))
 Me.Items.Remove(TryCast(item, DataItem))
 Me.Items.Insert(index - 1, TryCast(item, DataItem))
 Me.SelectedItem = item
End Sub
Public Sub MoveDown(sender As Object, e As ExecutedRoutedEventArgs)
 If Me.SelectedItem = Nothing OrElse Me.Items.IndexOf(TryCast(Me.SelectedItem, DataItem)) = Me.Items.Count - 1 Then
  Return
 End If
 Dim item As DataItem = Me.SelectedItem
 Dim index As Integer = Me.Items.IndexOf(TryCast(item, DataItem))
 Me.Items.Remove(TryCast(item, DataItem))
 Me.Items.Insert(index + 1, TryCast(item, DataItem))
 Me.SelectedItem = item
End Sub

Creating the CommandBindings

In order to use the commands in the UI you have to provide a CommandBinding for each of the commands. The CommandBinding binds the command to a method that is called when the command gets executed. The CommandBidnings get set via the CommandManager. As the CommandManager is called by the View you have to expose a method in your ViewModel that returns a collection of its CommandBindings.

CopyC#
public CommandBindingCollection GetCommandBindings()
{
    CommandBindingCollection bindings = new CommandBindingCollection();
    bindings.Add( new CommandBinding( this.MoveUpCommand, this.MoveUp ) );
    bindings.Add( new CommandBinding( this.MoveDownCommand, this.MoveDown ) );
    return bindings;
}
CopyVB.NET
Public Function GetCommandBindings() As CommandBindingCollection
 Dim bindings As New CommandBindingCollection()
 bindings.Add(New CommandBinding(Me.MoveUpCommand, Me.MoveUp))
 bindings.Add(New CommandBinding(Me.MoveDownCommand, Me.MoveDown))
 Return bindings
End Function

Setting the CommandBindings

In the View get the CommandBindingsCollection and set it through the CommandManager.

CopyC#
public CommandsSample()
{
    InitializeComponent();
    this.viewModel = new ExampleViewModel();
    this.DataContext = viewModel;
    CommandManager.SetCommandBindings( this, this.viewModel.GetCommandBindings() );
}
CopyVB.NET
Public Sub New()
 InitializeComponent()
 Me.viewModel = New ExampleViewModel()
 Me.DataContext = viewModel
 CommandManager.SetCommandBindings(Me, Me.viewModel.GetCommandBindings())
End Sub

See Also