In our previous blog about RadSpreadsheet we decided to do a quick warm up and show you how to plug the commands of RadSpreadsheet to a RadToolBar. Now it’s time to dive into RadSpreadsheet and learn tips and tricks about the other extension points of the control. Particularly, this post shows how to construct a context menu according to your needs and also, add items that execute custom commands. The context menu we will create will have two menu items for the copy and paste built-in commands and also a Highlight menu item for our custom command:
Taking a closer look at RadSpreadsheet reveals that, in fact, it does not have a built-in context menu. So, if you drop the control from the toolbox and run your app, right-clicking on the sheet’s cells will not display a menu. Why did we do it that way? Well, because it is very easy to build your own custom menu that contains only the items you need. Remember command descriptors from the RadSpreadsheet Tips and Tricks: RadToolBar in RadSpreadsheet – No Problem blog post? In case you don’t, command descriptors allow you to construct a context menu containing any combination of all available spreadsheet commands effortlessly! Each descriptor exposes a command and an IsEnabled property that indicates whether the command is currently available. Having said that, command descriptors are a powerful mechanism that allows you to bind any UI to a predefined spreadsheet command very easily.
For example, the following snippet sets up a context menu with two items: copy and paste. Of course, if you want to stick to the standard context menu, you can always get the code from the SDK example.
<
telerik:RadSpreadsheet
Grid.Row
=
"1"
x:Name
=
"radSpreadsheet"
DataContext
=
"{Binding Path=CommandDescriptors, ElementName=radSpreadsheet}"
>
<
telerik:RadSpreadsheet.WorksheetEditorContextMenu
>
<
telerik:RadContextMenu
>
<
telerik:RadMenuItem
Header
=
"Copy"
Command
=
"{Binding Path=Copy.Command}"
Visibility
=
"{Binding Path=Copy.IsEnabled, Mode=TwoWay, Converter={StaticResource BoolToVisibilityValueConverter}}"
>
<
telerik:RadMenuItem.Icon
>
<
Image
telerik:IconManager.IconPropertyName
=
"Source"
telerik:IconManager.IconSource
=
"/Telerik.Windows.Controls.Spreadsheet;component/Images/Light/16/copy.png"
Width
=
"16"
/>
</
telerik:RadMenuItem.Icon
>
</
telerik:RadMenuItem
>
<
telerik:RadMenuItem
Header
=
"Paste"
Command
=
"{Binding Path=Paste.Command}"
Visibility
=
"{Binding Path=Paste.IsEnabled, Mode=TwoWay, Converter={StaticResource BoolToVisibilityValueConverter}}"
>
<
telerik:RadMenuItem.Icon
>
<
Image
telerik:IconManager.IconPropertyName
=
"Source"
telerik:IconManager.IconSource
=
"/Telerik.Windows.Controls.Spreadsheet;component/Images/Light/16/pasteNormal.png"
Width
=
"16"
/>
</
telerik:RadMenuItem.Icon
>
</
telerik:RadMenuItem
>
</
telerik:RadContextMenu
>
</
telerik:RadSpreadsheet.WorksheetEditorContextMenu
>
</
telerik:RadSpreadsheet
>
Note that the data context of the spreadsheet is set to the CommandDescriptors property. Once descriptors are set as data context each of the RadMenuItems in the RadContextMenu can bind the Command and IsEnabled properties to any descriptor.
So, adding items that execute a command provided by the RadSpreadsheet API is seamless. That said, let’s see what happens when you would like to plug a custom command. For example, you may want to allow the user to highlight selected cells as special, which changes their background color to yellow. The highlight option should not be available if the currently selected cells have been already highlighted.
Let us start by specifying a command that invalidates whenever the selection changes. The following class inherits DelegateCommand class from the Telerik.Windows.Controls dll. The implementation invalidates the command’s CanExecute property whenever the selection of the current WorksheetEditor changes.
public
class
SelectionDependentCommand : DelegateCommand
{
private
readonly
RadSpreadsheet radSpreadsheet;
private
RadWorksheetEditor worksheetEditor;
public
SelectionDependentCommand(RadSpreadsheet radSpreadsheet, Action<
object
> action, Predicate<
object
> predicate)
:
base
(action, predicate)
{
this
.radSpreadsheet = radSpreadsheet;
this
.radSpreadsheet.ActiveSheetEditorChanged +=
this
.RadSpreadsheetActiveSheetEditorChanged;
}
private
void
RadSpreadsheetActiveSheetEditorChanged(
object
sender, EventArgs e)
{
if
(
this
.worksheetEditor !=
null
)
{
this
.worksheetEditor.Selection.SelectionChanged -=
this
.Selection_SelectionChanged;
}
this
.worksheetEditor =
this
.radSpreadsheet.ActiveWorksheetEditor;
if
(
this
.worksheetEditor !=
null
)
{
this
.worksheetEditor.Selection.SelectionChanged +=
this
.Selection_SelectionChanged;
}
}
private
void
Selection_SelectionChanged(
object
sender, EventArgs e)
{
this
.InvalidateCanExecute();
}
}
The next step is to instantiate the SelectionDependentCommand and plug it to the current context menu:
public
partial
class
MainWindow : Window
{
private
const
string
ContextMenuItemHeader =
"Highlight"
;
private
readonly
PatternFill highlightFill;
private
RadWorksheetEditor worksheetEditor;
public
MainWindow()
{
this
.highlightFill =
new
PatternFill(PatternType.Solid, Colors.Yellow, Colors.Transparent);
StyleManager.ApplicationTheme =
new
Windows8Theme();
InitializeComponent();
WorkbookFormatProvidersManager.RegisterFormatProvider(
new
XlsxFormatProvider());
this
.AddCustomContextMenuItem();
}
private
void
AddCustomContextMenuItem()
{
DelegateCommand highlightCommand =
null
;
Action<
object
> highlightCommandAction =
new
Action<
object
>((parameter) =>
{
this
.radSpreadsheet.ActiveWorksheetEditor.Selection.Cells.SetFill(highlightFill);
highlightCommand.InvalidateCanExecute();
});
Predicate<
object
> highlightCommandPredicate =
new
Predicate<
object
>((obj) =>
{
RadWorksheetEditor editor =
this
.radSpreadsheet.ActiveWorksheetEditor;
if
(editor !=
null
)
{
PatternFill patternFill = editor.Worksheet.Cells[editor.Selection.ActiveRange.SelectedCellRange].GetFill().Value
as
PatternFill;
if
(patternFill !=
null
)
{
return
!patternFill.Equals(highlightFill);
}
}
return
false
;
});
highlightCommand =
new
SelectionDependentCommand(
this
.radSpreadsheet, highlightCommandAction, highlightCommandPredicate);
RadMenuItem newItem =
new
RadMenuItem();
newItem.Header = ContextMenuItemHeader;
newItem.Command = highlightCommand;
this
.radSpreadsheet.WorksheetEditorContextMenu.Items.Add(newItem);
}
}
Now when you right-click the current selection the context menu contains the copy and paste commands along with the custom Highlight option:
Click the Highlight option and the background of all selected cells will turn yellow. Note that now if your selection includes highlighted cells, the option will not be available in the context menu:
That’s it! Now you know everything you need to create or change RadSpreadsheet’s Context Menu according to your needs. All the code you see here can be found in our SDK Examples. So make sure to check it out and play around with the source.
Stay tuned for more Spreadsheet customization tips and tricks!
Boryana Goncharenko,
Software Developer