Use a RadContextMenu in MVVM
This tutorial will show you how use a RadContextMenu with a RadGridView
It will show you how to do the following:
Define a RadContextMenu with MenuItems
First you need to define the context menu with menu items.
<local:ObjectToStringConverter x:Key="ObjectToStringConverter" />
<local:RadContextMenuXamlHolder x:Key="ContextMenuHolder">
<telerik:RadContextMenu DataContext="{Binding Path=UIElement.Column.DataControl.DataContext, RelativeSource={RelativeSource Self}}" InheritDataContext="False">
<telerik:RadMenuItem Command="{Binding SortAscendingCommand}"
CommandParameter="{Binding Path=Menu.UIElement,
RelativeSource={RelativeSource Self}}"
Header="{Binding Path=Menu.UIElement.Column.Header,
RelativeSource={RelativeSource Self},
Converter={StaticResource ObjectToStringConverter},
ConverterParameter='Sort Ascending by "{0}"'}" />
<telerik:RadMenuItem Command="{Binding SortDescendingCommand}"
CommandParameter="{Binding Path=Menu.UIElement,
RelativeSource={RelativeSource Self}}"
Header="{Binding Path=Menu.UIElement.Column.Header,
RelativeSource={RelativeSource Self},
Converter={StaticResource ObjectToStringConverter},
ConverterParameter='Sort Descending by "{0}"'}" />
<telerik:RadMenuItem Command="{Binding ClearSortCommand}"
CommandParameter="{Binding Path=Menu.UIElement,
RelativeSource={RelativeSource Self}}"
Header="{Binding Path=Menu.UIElement.Column.Header,
RelativeSource={RelativeSource Self},
Converter={StaticResource ObjectToStringConverter},
ConverterParameter='Clear Sorting by "{0}"'}" />
<telerik:RadMenuItem Command="{Binding GroupbyCommand}"
CommandParameter="{Binding Path=Menu.UIElement,
RelativeSource={RelativeSource Self}}"
Header="{Binding Path=Menu.UIElement.Column.Header,
RelativeSource={RelativeSource Self},
Converter={StaticResource ObjectToStringConverter},
ConverterParameter='Group by "{0}"'}" />
<telerik:RadMenuItem Command="{Binding UngroupCommand}"
CommandParameter="{Binding Path=Menu.UIElement,
RelativeSource={RelativeSource Self}}"
Header="{Binding Path=Menu.UIElement.Column.Header,
RelativeSource={RelativeSource Self},
Converter={StaticResource ObjectToStringConverter},
ConverterParameter='Ungroup by "{0}"'}" />
<telerik:RadMenuItem Header="Choose Columns:" ItemsSource="{Binding Path=Menu.UIElement.Column.DataControl.Columns, RelativeSource={RelativeSource Self}}">
<telerik:RadMenuItem.ItemContainerStyle>
<Style TargetType="telerik:RadMenuItem">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="IsChecked" Value="{Binding IsVisible, Mode=TwoWay}" />
<Setter Property="IsCheckable" Value="True" />
</Style>
</telerik:RadMenuItem.ItemContainerStyle>
</telerik:RadMenuItem>
</telerik:RadContextMenu>
</local:RadContextMenuXamlHolder>
Create a style for the column headers
You need to attach the defined context menu to the column headers.
<Style TargetType="telerik:GridViewHeaderCell">
<Setter Property="telerik:RadContextMenu.ContextMenu" Value="{Binding Path=ContextMenu, Source={StaticResource ContextMenuHolder}}" />
</Style>
Define the RadGridView
The style targeting GridViewHeaderCell will be automatically applied for the RadGridView
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ViewModel}">
<telerik:RadGridView ItemsSource="{Binding Items}" />
</Grid>
Implementaions in code behind
The RadContextMenuXamlHolder class is defined in code behind like so:
[ContentProperty("ContextMenu")]
public class RadContextMenuXamlHolder : INotifyPropertyChanged
{
private RadContextMenu contextMenu;
public event PropertyChangedEventHandler PropertyChanged;
public RadContextMenu ContextMenu
{
get
{
return this.contextMenu;
}
set
{
if (this.contextMenu != value)
{
this.contextMenu = value;
this.RaisePropertyChanged("ContextMenu");
}
}
}
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The RadContextMenuXamlHolder class is defined as follows:
public class ObjectToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.Format(System.Convert.ToString(parameter), value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The implementation of the ViewModel is below:
public ViewModel()
{
this.Items = LoadData();
this.SortAscendingCommand = new DelegateCommand(OnSortAscending, CanSortAscending);
this.SortDescendingCommand = new DelegateCommand(OnSortDescending, CanSortDescending);
this.ClearSortCommand = new DelegateCommand(OnClearSort, CanClearSort);
this.GroupbyCommand = new DelegateCommand(OnGroupby, CanGroupby);
this.UngroupCommand = new DelegateCommand(OnUngroup, CanUngroup);
}
public DelegateCommand SortAscendingCommand { get; private set; }
public DelegateCommand SortDescendingCommand { get; private set; }
public DelegateCommand ClearSortCommand { get; private set; }
public DelegateCommand GroupbyCommand { get; private set; }
public DelegateCommand UngroupCommand { get; private set; }
public IEnumerable Items
{
get;
private set;
}
private static void Sort(GridViewHeaderCell cell, ListSortDirection sortDirection)
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnSortDescriptor sd = (from d in grid.SortDescriptors.OfType<ColumnSortDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (sd != null)
{
grid.SortDescriptors.Remove(sd);
}
ColumnSortDescriptor newDescriptor = new ColumnSortDescriptor();
newDescriptor.Column = cell.Column;
newDescriptor.SortDirection = sortDirection;
grid.SortDescriptors.Add(newDescriptor);
}
private void OnSortAscending(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.Ascending)
{
Sort(cell, ListSortDirection.Ascending);
}
}
private bool CanSortAscending(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.CanSort() && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.Ascending)
{
return true;
}
return false;
}
private void OnSortDescending(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.CanSort() && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.Descending)
{
Sort(cell, ListSortDirection.Descending);
}
}
private bool CanSortDescending(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.CanSort() && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.Descending)
{
return true;
}
return false;
}
private void OnClearSort(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.CanSort() && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.None)
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnSortDescriptor sd = (from d in grid.SortDescriptors.OfType<ColumnSortDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (sd != null)
{
grid.SortDescriptors.Remove(sd);
}
}
}
private bool CanClearSort(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.CanSort() && cell.Column.DataControl != null && cell.Column.SortingState != SortingState.None)
{
return true;
}
return false;
}
private void OnGroupby(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.DataControl != null && cell.Column.CanGroup())
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnGroupDescriptor gd = (from d in grid.GroupDescriptors.OfType<ColumnGroupDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (gd == null)
{
ColumnGroupDescriptor newDescriptor = new ColumnGroupDescriptor();
newDescriptor.Column = cell.Column;
newDescriptor.SortDirection = ListSortDirection.Ascending;
grid.GroupDescriptors.Add(newDescriptor);
}
}
}
private bool CanGroupby(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.DataControl != null && cell.Column.CanGroup())
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnGroupDescriptor gd = (from d in grid.GroupDescriptors.OfType<ColumnGroupDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (gd == null)
{
return true;
}
}
return false;
}
private void OnUngroup(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.DataControl != null && cell.Column.CanGroup())
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnGroupDescriptor gd = (from d in grid.GroupDescriptors.OfType<ColumnGroupDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (gd != null)
{
grid.GroupDescriptors.Remove(gd);
}
}
}
private bool CanUngroup(object parameter)
{
GridViewHeaderCell cell = parameter as GridViewHeaderCell;
if (cell != null && cell.Column != null && cell.Column.DataControl != null && cell.Column.CanGroup())
{
RadGridView grid = cell.Column.DataControl as RadGridView;
ColumnGroupDescriptor gd = (from d in grid.GroupDescriptors.OfType<ColumnGroupDescriptor>()
where object.Equals(d.Column, cell.Column)
select d).FirstOrDefault();
if (gd != null)
{
return true;
}
}
return false;
}
private static List<Order> LoadData()
{
// return data
return new List<Order>();
}
}
The defined ContextMenu works
A sample project can be downloaded here. You can also check Header Context Menu and Row Context Menu WPF Demos.