Edit this page

Use Commands with the RadContextMenu

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.

XAML

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

C#

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

VB.NET

Public Class ExampleViewModel
    Implements INotifyPropertyChanged
    Private selectedItemField As DataItem
    Public Sub New()
        Me.InitItems()
    End Sub
    Public Property Items() As ObservableCollection(Of DataItem)
        Get
        End Get
        Set(value As ObservableCollection(Of DataItem))
        End Set
    End Property
    Public Property SelectedItem() As DataItem
        Get
            Return Me.selectedItemField
        End Get
        Set(value As DataItem)
            If Me.selectedItemField Is value Then
                Me.selectedItemField = value
                Me.NotifyPropertyChanged("SelectedItem")
            End If
        End Set
    End Property

    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

    Public Event PropertyChanged As PropertyChangedEventHandler _
        Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    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.

C#

private ExampleViewModel viewModel;
public Default_Cs()
{
    InitializeComponent();
    this.viewModel = new ExampleViewModel();
    this.DataContext = viewModel;
}

VB.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.

XAML

<ListBox x:Name="listBox1"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu1">
        </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.

XAML

<ListBox x:Name="listBox2"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu2"
                                  Opened="RadContextMenu_Opened">
        </telerik:RadContextMenu>
    </telerik:RadContextMenu.ContextMenu>
</ListBox>

C#

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

VB.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 Is 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.

C#

public RoutedUICommand MoveUpCommand
{
    get;
    private set;
}
public RoutedUICommand MoveDownCommand
{
    get;
    private set;
}

VB.NET

Public Property MoveUpCommand() As RoutedUICommand
    Get
    End Get
    Private Set(value As RoutedUICommand)
    End Set
End Property
Public Property MoveDownCommand() As RoutedUICommand
    Get
    End Get
    Private Set(value As RoutedUICommand)
    End Set
End Property

Initialize them in the constructor of the ViewModel:

C#

public ExampleViewModel()
{
    this.MoveUpCommand = new RoutedUICommand("Move Up", "MoveUp", typeof(ExampleViewModel));
    this.MoveDownCommand = new RoutedUICommand("Move Down", "MoveDown", typeof(ExampleViewModel));
    this.InitItems();
}

VB.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.

XAML

<ListBox x:Name="listBox3"
         DisplayMemberPath="Value"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <telerik:RadContextMenu.ContextMenu>
        <telerik:RadContextMenu x:Name="radContextMenu3"
                                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.

C#

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

VB.NET

Public Sub MoveUp(sender As Object, e As ExecutedRoutedEventArgs)
    If Me.SelectedItem Is 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 Is 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.

C#

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

VB.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.

C#

public Default_Cs()
{
    InitializeComponent();
    this.viewModel = new ExampleViewModel();
    this.DataContext = viewModel;
    CommandManager.SetCommandBindings(this, this.viewModel.GetCommandBindings());
}

VB.NET

Public Sub New()
    InitializeComponent()
    Me.viewModel = New ExampleViewModel()
    Me.DataContext = viewModel
    CommandManager.SetCommandBindings(Me, Me.viewModel.GetCommandBindings())
End Sub

See Also