I would like to add support to my RadDiagram for the user to perform a multi-select operation using the Shift key, in addition to the default Ctrl key. I looked at adding to the InputBindings but there is no Command for select. I also tried adding a handler for OnSelectionChanged that attempted to re-select the items in the SelectionChangedEventArgs.RemovedItems but my changes were apparently overridden after the handler completed and only the last clicked item would be selected.
Is there a way to implement this?
Thanks,
Peter Pepperell
6 Answers, 1 is accepted
As RadDiagram doesn't support this functionality out-of-the-box you can achieve your requirements with custom logic. You can handle the KeyDown, SelectionChanged and PreviewSelectionChanged events of the diagram.
In the KeyDown handler you will need to check if the Shift and the left mouse button are down. If so, you can use the Diagram HitTestService to select the shape which is under the mouse and then select it with the SelectionService.SelectItem() method. Note that the second parameter of the SelectedItem() method controls if the item should be added in the current selected items collection. You can read more about the Diagram Services in our help.
private
HitTestService hitTestService;
private
SelectionService selectionService;
public
MainWindow()
{
InitializeComponent();
this
.AddHandler(RadDiagram.KeyDownEvent,
new
KeyEventHandler(OnKeyDown),
true
);
hitTestService =
this
.diagram.ServiceLocator.GetService<IHitTestService>()
as
HitTestService;
selectionService =
this
.diagram.ServiceLocator.GetService<ISelectionService<IDiagramItem>>()
as
SelectionService;
}
private
void
OnKeyDown(
object
sender, KeyEventArgs args)
{
bool
isShiftKeyDown = (args.Key == Key.LeftShift || args.Key == Key.RightShift);
bool
isLeftMouseButtonDown = Mouse.LeftButton == MouseButtonState.Pressed;
if
(isShiftKeyDown && isLeftMouseButtonDown )
{
this
.selectionService.SelectItem(
this
.hitTestService.ItemUnderMouse,
true
);
}
}
The logic in the Diagram.PreviewSelectionChanged checks if the Shift key is down and if there are any items in the RemovedItems collection. If so, handle the event with e.Handled = true.
private
void
diagram_PreviewSelectionChanged(
object
sender, SelectionChangedEventArgs e)
{
bool
isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if
(isShiftKeyDown && e.RemovedItems.Count != 0)
e.Handled =
true
;
}
private
void
diagram_SelectionChanged(
object
sender, SelectionChangedEventArgs e)
{
bool
isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if
(isShiftKeyDown)
{
var shapes = hitTestService.GetShapesUnderRect(diagram.SelectionBounds);
foreach
(RadDiagramShape shape
in
shapes)
{
shape.IsSelected =
true
;
}
}
}
I attached a sample project with this implementation which you can use as a base for your requirements.
Regards,
Martin
Telerik
DevCraft Q1'14 is here! Join the free online conference to see how this release solves your top-5 .NET challenges. Reserve your seat now!
Thanks for the sample code, it works for my needs, but only to a point. I want the Shift key to have the same behavior as the Ctrl key does, including deselecting individual items (when already selected) but leaving the remaining selected items unchanged.
I made some changes to the sample you sent, but I was unable to achieve the desired result.
Can you show me what changes need to be made to your previous sample code to make the Shift+Click key combo mimic the behavior of the Ctrl+Click?
Thanks,
Peter
In order to add this functionality you will need to do few changes in the last project that I send you. It seems that the KeyDown event is called too early that's why we should move our selection/deselection logic in the Diagram ShapeClick event handler and then made some changes. Here is an example in code:
private
void
diagram_ShapeClicked(
object
sender, Telerik.Windows.Controls.Diagrams.ShapeRoutedEventArgs e)
{
bool
isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if
(isShiftKeyDown)
{
toolService.DeactivateTool(toolService.ToolList[0]);
if
(e.Shape.IsSelected)
{
this
.selectionService.DeselectItem(e.Shape);
}
else
{
this
.selectionService.SelectItem(e.Shape,
true
);
}
}
}
private
void
diagram_MouseLeftButtonUp(
object
sender, MouseButtonEventArgs e)
{
toolService.ActivateTool((toolService.ToolList[0]
as
ToolBase).Name);
}
Note that we are deactivating the PointerTool from the tools of the ToolService. Otherwise the selection will be triggered twice. Once for our custom selection and second time for the default selection. The PointerTool controls how the selection in the Diagram should be handled. After our custom selection we should activate this tool again in order for the default selection to work correctly. You can read more about the tools in the Tools Customization help article.
I also attached an updated project with this implementation. I hope this is helpful.
Regards,
Martin
Telerik
DevCraft Q1'14 is here! Watch the online conference to see how this release solves your top-5 .NET challenges. Watch on demand now.
Ok, I played around with the sample code above and came up with the following changes which seem to work just fine. The only thing which bothers me is that I made less changes then described above so I'm wondering if there are scenarios where my code will not work or have undesired side effects?
In the previewSelectionChanged event handler I added an additional condition for the e.Handled to be set to True and this was needed to get the 'deselect' to work (when pressing the Shift key and clicking on a selected shape).
DiagramControl.PreviewSelectionChanged += DiagramControl_PreviewSelectionChanged;
DiagramControl.ShapeClicked += DiagramControl_ShapeClicked;
m_diagramSelectionService = DiagramControl.ServiceLocator.GetService<ISelectionService<IDiagramItem>>()
as
SelectionService;
void
DiagramControl_ShapeClicked(
object
sender, ShapeRoutedEventArgs e)
{
bool
isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if
(isShiftKeyDown)
{
if
(e.Shape.IsSelected)
{
m_diagramSelectionService.DeselectItem(e.Shape);
}
else
{
m_diagramSelectionService.SelectItem(e.Shape,
true
);
}
}
}
void
DiagramControl_PreviewSelectionChanged(
object
sender, SelectionChangedEventArgs e)
{
bool
isShiftKeyDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if
(isShiftKeyDown && e.RemovedItems.Count != 0 && e.AddedItems.Count != 0)
{
e.Handled =
true
;
}
}
We had a technical issue with the attachments in the forum. The issue is already fixed so you should be able to download the .zip with the project.
About your implementation, well at first sight I cannot tell if you are going to experience any undesired effects. But as this is a custom solution I won't be surprised if it happens. This is why I recommend you test all expected scenarios.
Regards,
Martin
Telerik by Progress