Drag&Drop from external and visual effect

Hello,

I am using the GoXAM diagram hosted inside a Windows forms application. I have a tree from which the user shall be able to drag&drop into the diagram. Those objects are represented in the diagram by nodes. Functionally, I have already everything working. But I would like to improve the user experience. Until now, one only sees the copy-cursor during dragging. When the mouse enters the diagram during the dragging, I would like to already show a node with the data of the drag&drop.
I already searched the examples but wasn’t able to find a good starting Point.
In the doc for DraggingTool.DoDragOver I read sth. about that one has to create the parts, but I don’t know how to do that and what exactly I have to do so I see a node during the dragging.

Any help is appreciated,
Marc

In your already-working app, what event handlers and method overrides have you implemented that involving dragging?

And what (if anything) have you done to try to implement what you are asking about in this topic?

Hi Walter,

I’m dragging objects from a treeview, that, in the diagram, should be represented as nodes. Thus, I implemented an ItemDrag Event handler for the tree view like this:

private void TreeViewWorkstepdefinitionsOnItemDrag(object sender, ItemDragEventArgs e)
{
	// the Tag attribute of the tree node holds the corresponding business model of the tree node
	var dragDropData = (e.Item as TreeNode).Tag;

	if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
	{
		this.DoDragDrop(dragDropData, DragDropEffects.Copy);
	}
}

I then implemented a listener for the Drop Event of the diagram:

private void DiagramOnDrop(object sender, System.Windows.DragEventArgs dragEventArgs)
{
	dragEventArgs.Handled = true;

	// dragging a workstepdefinition from the workstepdefinition treeview to create a new node in the diagram
	if (dragEventArgs.Data.GetDataPresent(typeof(STOWorkstepdefinitionDTOImpl)))
	{
		// create a new view model for the dropped data and add it to the Diagram's node collection
		var dragDropData = dragEventArgs.Data.GetData(typeof(STOWorkstepdefinitionDTOImpl)) as STOWorkstepdefinitionDTOImpl;
		var node = new STOWorkstepdefinitionNodeData(dragDropData);
		node.NodeCategory = "NewNodeTemplate";
		this.WrapInModelTransaction("add node", () => diagram.Model.AddNode(node));

		// set the drop position of the node
		var currentPosition = dragEventArgs.GetPosition(diagram);
		node.Location = diagram.Panel.TransformViewToModel(currentPosition);
		diagram.Nodes.First(x => x.Data == node).IsSelected = true;
	}
}

Plus, I implemente a listener for the DragOver Event to disable dropping onto an existing node like following:

private void DiagramOnDragOver(object sender, System.Windows.DragEventArgs dragEventArgs)
{
	dragEventArgs.Handled = true;
	if (this.Model.IsReadOnly)
	{
		dragEventArgs.Effects = System.Windows.DragDropEffects.None;
		return;
	}

	dragEventArgs.Effects = System.Windows.DragDropEffects.Copy | System.Windows.DragDropEffects.Move;
	var point = diagram.Panel.TransformViewToModel(dragEventArgs.GetPosition(diagram));
	var node = diagram.Panel.FindPartAt<Node>(point, n => true, SearchLayers.All);
	if (node != null)
	{
		dragEventArgs.Effects = System.Windows.DragDropEffects.None;
	}
}

I then started to take a look at the DraggingTool but have no real glue what exactly I have to do to make a node appear as soon as the dragging is over the diagram area. As mentioned in my request, I read sth. about that one would have to create parts. But until now, I didn’t create parts (programmatically) and don’t know exactly how to create them and what to do with them if they are created.
I’m also totally unsure if the way i implemented the drag & drop is ok or if everything should be handled by the dragging tool (if this would be possible).

Kind regards,
Marc

I don’t have an example of dragging a treenode from a Windows Forms treeview, but I do have an example of that in WPF. I’ll assume the GoXam model uses a node data class named TestData.

In the simplest form, create a TreeView that contains instances of TestData:

      <TreeView x:Name="myTreeView" Width="150" Height="100"
                SelectedValuePath="Header" MouseMove="myTreeView_MouseMove">
        <TreeViewItem Header="Root">
          <TreeViewItem>
            <TreeViewItem.Header>
              <local:TestData Name="First Data" />
            </TreeViewItem.Header>
          </TreeViewItem>
          <TreeViewItem>
            <TreeViewItem.Header>
              <local:TestData Name="Second Data" />
            </TreeViewItem.Header>
          </TreeViewItem>
        </TreeViewItem>
      </TreeView>

The MouseMove event handler could be defined as:

    private void myTreeView_MouseMove(object sender, MouseEventArgs e) {
      if (e.LeftButton == MouseButtonState.Pressed && myTreeView.SelectedItem != null) {
        DragDrop.DoDragDrop(myTreeView, myTreeView.SelectedValue, DragDropEffects.Copy);
      }
    }

Hello Walter,

first of all - thanks for your reply.

Having read your example, I became an idea what the reason was that I do not see a node while dragging. It’s because the data object that is being dragged simply is not a node - as it is in your example code. I changed that and now I see a node while dragging.

The object I pack into the DoDragDrop method is a Business model on which a node in the diagram is based upon. I can Change my impl. to pack the node in it. But somehow I got the Impression, that I could do a conversion (i.e. create a node for the Business model) later in the dragging process when the dragging enters the diagram control (e.g. in DraggingTool:DoDragOver). But perhaps I misunderstood the documentation there.

For an external move (<see cref="M:Northwoods.GoXam.Tool.DraggingTool.MayMoveExternal(System.Windows.DragEventArgs)"/>), create parts from the external drag-and-drop data and move them appropriately.

So, if it is the “preferred” way to drag already parts instead of arbitrary objects into the diagram I will do this.

Kind regards,
Marc

I don’t know about “preferred” way, but it’s certainly the “easy” way.

If you wanted to drag in data other than what the model is dealing with, you’d need to override some methods. I’m not sure off-hand, but it might be sufficient to override DraggingTool.MayAcceptData and DraggingTool.AcceptData.