10 Answers, 1 is accepted
You can use the RadDiagram DraggingService to track the changes of a shape's position while dragging it. Please take a look at the Services article in our documentation to get a better understanding if the services exposed by the Diagramming Framework and how to access them.
In your particular case, you can attach an event handler to the DraggingService Dragging event handler:
xDiagram.ServiceLocator.GetService<IDraggingService>().Dragging +=
new
EventHandler<PositionChangedEventArgs>(OnDiagramItemsDragging);
void
OnDiagramItemsDragging(
object
sender, PositionChangedEventArgs e)
{
var draggedItems = e.Items;
if
(e.Items.Count() > 0)
{
RadDiagramShape draggedShape = e.Items.FirstOrDefault()
as
RadDiagramShape;
if
(draggedShape.Position.X < 0 || draggedShape.Position.Y < 0)
{
xDiagram.Background =
new
SolidColorBrush(Colors.Wheat);
}
else
xDiagram.Background =
null
;
}
}
Please give this a try and let me know if it helps.
Regards,
Tina Stancheva
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
The event is generated when moving with mouse. But how to intercept the movement with the keyboard (ctrl + arrow)?
Thank you in advance,
Best regards,
Yann
The diagram doesn't provide an event that is fired when you move a shape with the keyboard. However, you can listen for moving of items in the RadDiagram if you subscribe for its CommandExecuted event and check if the executed command has its Name property set to "Move Items". Here is an example in code:
private
void
diagram_CommandExecuted(
object
sender, CommandRoutedEventArgs e)
{
if
(e.Command.Name ==
"Move Items"
)
{
// execute your logic
}
}
Please let me know if this helps.
Regards,
Martin
Telerik
Hi Martin,
I need to prevent moving some shapes outside a predefined area.
Using the "how to restrict the draggable area" of the raddiagram documentation (http://docs.telerik.com/devtools/wpf/controls/raddiagram/howto/customize-dragging), I was able to restrict the dragging of the shapes to the area I wanted.
BUT
this applies only when moving the shapes with the mouse, as Yann pointed out. Which means that once I release the mouse and the shape is right on the edge of the area, I can move it with the keyboard OUTSIDE the area. This is what I would like to prevent
I have tried using your suggestion, but the problem is that this event happens AFTER the items are moved. This would still be fine with me, since I could just move the shapes back, but the issue with this is that in this even manager I don't have access to the details of the command executed, namely: I do not know in which direction the shapes where moved, neiter the amount of pixels they where moved by.
is there any other way I can prevent moving the shapes with the keyboard outside of a predefined area ?
hi again,
nevermind, I figured out a way to do what I wanted, even though it is kind of dirty :
// if shape is moved out of the boundaries :
this.Diagram.Undo();
while (this.Diagram.UndoRedoService.RedoStack.Any())
this.Diagram.UndoRedoService.RemoveCommand(this.Diagram.UndoRedoService.RedoStack.Last());
that being said, it would be great to have a way to override the default behavior of the "move item" command, because as it is right now, it looks kind of unfinished :-/ (the fact taht there is a way to restrict the dragging area but not the "nudging" area is kind of useless)
Thank you for sharing your solution with the forum community.
Another approach is to override the default nudge command and implement custom logic that checks if the nudge (move items) action is allowed.
I also attached a small example that demonstrates an approach with a new command. Basically, you can replace the input bindings for the nudge command (Ctrl+Up, Ctrl+Down, Ctrl+Left, Ctrl+Right) with input bindings for a new custom command which will call the DiagramCommands.Nudge.Execute() in its OnExecute handler.
public
static
class
MyDiagramCommands
{
public
static
RoutedUICommand Nudge;
static
MyDiagramCommands()
{
Nudge =
new
RoutedUICommand(
"Moves the items"
,
"Nudge"
,
typeof
(RadDiagram));
}
}
private
void
ReplaceNudgeCommand()
{
var commandBinding =
new
CommandBinding(MyDiagramCommands.Nudge, OnNudgeExecute, OnCanNudgeExecute);
CommandManager.RegisterClassCommandBinding(
typeof
(RadDiagram), commandBinding);
var rightKeyBinding =
new
KeyBinding(MyDiagramCommands.Nudge,
new
KeyGesture(Key.Right, ModifierKeys.Control));
var leftKeyBinding =
new
KeyBinding(MyDiagramCommands.Nudge,
new
KeyGesture(Key.Left, ModifierKeys.Control));
var upKeyBinding =
new
KeyBinding(MyDiagramCommands.Nudge,
new
KeyGesture(Key.Up, ModifierKeys.Control));
var downKeyBinding =
new
KeyBinding(MyDiagramCommands.Nudge,
new
KeyGesture(Key.Down, ModifierKeys.Control));
this
.diagram.InputBindings.Add(rightKeyBinding);
this
.diagram.InputBindings.Add(leftKeyBinding);
this
.diagram.InputBindings.Add(upKeyBinding);
this
.diagram.InputBindings.Add(downKeyBinding);
}
private
void
OnCanNudgeExecute(
object
sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute =
true
;
}
private
void
OnNudgeExecute(
object
sender, ExecutedRoutedEventArgs e)
{
(if the nudge is allowed)
{
DiagramCommands.Nudge.Execute(
"LeftSmall"
,
this
.diagram);
// note that you will need to call the command with different parameter based on the pressed key
// The allow values are "Left", "Right", "Up", "Down". You can also specify the step in the parameter after the direction, ex: "Left:15px", "Left:Small".
}
}
Regards,
Martin
Telerik
Hi Martin,
thanks for your answer. Your solution is way cleaner than mine and I'll definitely do that. That's actually what I tried to do at first, but without success, since I could not find a way to override the Nudge command. I was missing the whole keybindings part.
PS : you should definitely add this to the telerik documentation, in the HowTo section! that's not trivial and pretty useful in my opinion
Well, I really am having trouble with this...
here is what I did, as a test :
in xaml :
<
telerik:RadDiagram
Name
=
"Diagram"
Background
=
"White"
IsEditable
=
"False"
IsRotationEnabled
=
"false"
IsConnectorsManipulationEnabled
=
"False"
AllowCopy
=
"False"
AllowCut
=
"False"
AllowPaste
=
"False"
AllowDrop
=
"False"
ShapeStyleSelector
=
"{StaticResource CustomShapeStyleSelector}"
CommandExecuted
=
"Diagram_CommandExecuted"
>
<
telerik:RadDiagram.CommandBindings
>
<
CommandBinding
Command
=
"telerik:DiagramCommands.Nudge"
CanExecute
=
"NudgeCommandCanExecute"
Executed
=
"NudgeCommandExecuted"
/>
</
telerik:RadDiagram.CommandBindings
>
</
telerik:RadDiagram
>
then, in c# :
private void NudgeCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;
}
private void NudgeCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("hello!!!");
}
private void Diagram_CommandExecuted(object sender, CommandRoutedEventArgs e)
{
if (e.Command.Name == "Move Items")
{
MessageBox.Show("Command Executed");
}
}
since I put e.CanExecute in my NudgeCommandCanExecute, I am expecting the program to do nothing at All (no "Hello!!!" and no "Command Executed")
but... I get the "Command Executed", and the item is moved in the diagram.
If I set e.CanExecute = true, I get both the "Hello!!!" and the "Command Executed", which is as expected.
Now, Why is the "e.canExecute = false" not taken FULLY into account ? I can see that It prevents the execution of NudgeCommandExecuted(), but it still allows the Diagram to do something with the items, since they are moved
is there something I am missing here ?
Aaaaaand I'm back (sorry for spamming, I'd like to delete my previous posts but can't :-/)
I managed to get everything going in the end. The issue was that I was binding Directly on the DiagramCommands.Nudge command. I thought I could be lazy on this one, but apparently, that was a very poor idea. so I created my own Nudge Command as you advised, got all the keybindings going and this achieves what I want.
for those interested, it's a little bit more tedious than what I hoped:
<
telerik:RadDiagram
Name
=
"Diagram"
Background
=
"White"
IsEditable
=
"False"
IsRotationEnabled
=
"false"
IsConnectorsManipulationEnabled
=
"False"
AllowCopy
=
"False"
AllowCut
=
"False"
AllowPaste
=
"False"
AllowDrop
=
"False"
ShapeStyleSelector
=
"{StaticResource CustomShapeStyleSelector}"
>
<
telerik:RadDiagram.CommandBindings
>
<
CommandBinding
Command
=
"local:MyDiagramCommands.Nudge"
CanExecute
=
"NudgeCommandCanExecute"
Executed
=
"NudgeCommandExecuted"
/>
</
telerik:RadDiagram.CommandBindings
>
<
telerik:RadDiagram.InputBindings
>
<
KeyBinding
Gesture
=
"Control+Left"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Left"
/>
<
KeyBinding
Gesture
=
"Control+Right"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Right"
/>
<
KeyBinding
Gesture
=
"Control+Up"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Up"
/>
<
KeyBinding
Gesture
=
"Control+Down"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Down"
/>
<
KeyBinding
Gesture
=
"Control+Shift+Left"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Left;Large"
/>
<
KeyBinding
Gesture
=
"Control+Shift+Right"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Right;Large"
/>
<
KeyBinding
Gesture
=
"Control+Shift+Up"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Up;Large"
/>
<
KeyBinding
Gesture
=
"Control+Shift+Down"
Command
=
"local:MyDiagramCommands.Nudge"
CommandParameter
=
"Down;Large"
/>
</
telerik:RadDiagram.InputBindings
>
</
telerik:RadDiagram
>
public static class MyDiagramCommands
{
public static RoutedUICommand Nudge;
static MyDiagramCommands()
{
Nudge = new RoutedUICommand("Move Items", "Nudge", typeof(RadDiagram));
}
}
and:
public static class MyDiagramCommands
{
public static RoutedUICommand Nudge;
static MyDiagramCommands()
{
Nudge = new RoutedUICommand("Move Items", "Nudge", typeof(RadDiagram));
}
}
and:
private void NudgeCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true; // or false depending on some stuff
}
private void NudgeCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
DiagramCommands.Nudge.Execute(e.Parameter, this.Diagram);
}
all in all, not so bad, But I would be Reeeeeeally great to have the ability to restrict the NudgeArea just As it is possible to restrict the DragArea when dragging. Food for thoughts!
thanks again,
I am glad to hear that the suggested solution works for you. As for the approach you tried after this, actually you can make it work but there are few things that should keep in mind. So, you can register directly the DiagramCommands,Nudge command, but this won't completely override the command behavior already defined but it will add the new one. If the last registered command handler (behavior) can't be executed the framework will bubble to the previous one (which is the default diagram nudge action). This is why when you set the e.CanExecute to False, the default nudge is executed. In order to prevent this, after setting the e.CanExecute property to False, you can also set the e.Handled to True. This will prevent the command events from bubbling and the default logic won't be executed.
private
void
NudgeCommandCanExecute(
object
sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute =
false
;
e.Handled =
true
;
}
However, if you completely override the Nudge command you will need to write its logic from scratch. Calling the DiagramCommands.Nudge.Execute() method in the OnExecute handler will gets you into an endless recursion. I gave you the approach from my last reply so you won't need to write the whole nudge from the beginning.
I hope this information is useful.
Regards,
Martin
Telerik