Drag&Drop multiple items (Win Forms -> WPF) problem

Hello,

I already implemented drag & drop from Windows Forms into a hosted GoXAM diagram for a single node.
Now I recognized in my spec, that the node one can drag into the diagram also has to have a self reference link.
Thus I created a data collection and added the node and the link into it.
Then I start the drag & drop Operation which causes a System.ComponentModel.Win32Exception. It’s message says: “Clipboard format registration did not succeed”, the stack is “at System.Windows.Forms.DataFormats.GetFormat(String format)”

Here’s my code:

var dataCollection = this.diagram.Model.CreateDataCollection();
dataCollection.AddNode(node);
dataCollection.AddLink(selfReferenceLink);
this.DoDragDrop(dataCollection, DragDropEffects.Copy);

Any ideas? As stated earlier, passing a single node works, but I have to pass also the link now. Both the node and the link classes are also marked Serializable.

Thanks in advance,
Marc

That looks good to me. Internally GoXam does the same thing when dragging the selection.

What’s the data format? (The IDiagramModel.DataFormat.)

the DataFormat is the fqn of my graph links model implementation

Have you defined a subclass of GraphLinksModel (or some other GoXam model class)?

I’m sorry I can’t think of what the problem might be; I don’t recall ever having seen that before.

Yes. I defined a specialization:

public class STOWorkflowGraphLinksModel : GraphLinksModel<STOWorkstepdefinitionNodeData, string, string, STOWorkflowLinkDataBase>

I’m still experimenting a bit. With following code I succeeded to workaround the exception, but now run into other Problems. But first the Workaround:

var dataCollection = this.Model.CreateDataCollection();
dataCollection.AddNode(node);
dataCollection.AddNode(otherNode);
dataCollection.AddLink(selfReferenceLink);
System.Windows.DataObject dataObject = new System.Windows.DataObject(this.Model.DataFormat, dataCollection);
this.DoDragDrop(dataObject, DragDropEffects.Copy);

With this code I’m able to drag multiple nodes into the diagram. BUT somehow the link I add to the data collection somehow doesn’t make it into the diagram. Perhaps anything I could make wrong there? The link’s type is a derived class of GraphLinksModelLinkData<string,string>. I create it like this:

var selfReferenceLink = new STOWorkflowdefinitionLinkData(workflowdefinition)
{
	From = node.Key,
	FromPort = STOPortIds.PortBottom.ToString(),
	To = node.Key,
	ToPort = STOPortIds.PortTop.ToString()
};

Is there perhaps some method that should be called for creating the link where I could set a break Point to see if it gets called?

Kind regards,
Marc

Is that selfReferenceLink using the node keys of the nodes in the dataCollection, not the node keys in the diagram’s model?

I’m not sure if I understand your question. I think yes. The link uses the node keys of the nodes which are in the dataCollection. But the keys of These nodes when they are added to the diagram are the same.
But I found out the following by Debugging. When the dragging runs, the method InsertLink() is called. And the link data with which this method is called doesn’t have the key Information anymore. It has the right ports (bottom => top), but the node references are lost. What is somehow strange because when I look at the data in AcceptData in the dragging tool which is called a moment earlier, the Information is there. InsertLink is called by AddLink and from the method CopyCollection if I remember it correctly.

Do you see anything here that makes sense to you?

Kind regards,
Marc

The DraggingTool, after calling AcceptData, calls AddCollectionCopy in order to copy the data into the diagram’s model. That’s what’s calling CopyLink1, CopyLink2, and AddLink, which calls InsertLink. AddCollectionCopy works in two passes to make sure the references are handled correctly (see its documentation).

Then the DraggingTool shifts the new parts and remembers everything as the DraggingTool.CopiedParts dictionary.

Maybe CopyLink1 isn’t doing what you want? It should be working if the link data class is ICloneable or if it is Serializable.

Maybe CopyLink2 isn’t doing what you want? Are the GraphLinksModel.LinkFromPath and GraphLinksModel.LinkToPath what you would expect?

Hi,

first of all. Thanks for this Information. I had no glue :frowning:

I don’t understand for sure what’s going on. Debugging Shows following:

  • CopyLink1() is called and produces a link data without the references to the connected nodes
  • then, InsertLink() is called with the result of CopyLink1(), i.e. the link without the references
  • then, CopyLink2() is invoked, there, it seems that the references to the nodes exist and Point to the correct nodes

But in the documentation it says:

You will want to override this method if the link data should have any references to copied data. Otherwise the copied link will appear to connect the original nodes, not the copied nodes. 

I currently cannot tell if the node references in CopyLink2() Point to the original nodes of the dragging Operation or to copies. I may have to investigate. Is there a reason why one has to do this? Why are the references to nodes not automatically set to their copies?

Kind regards,
Marc

Wait a Moment. Just read sth. important:

When ValidUnconnectedLinks is ValidUnconnectedLinks.None (the default value), if either newfromnodedata or newtonodedata is null, this will remove the copied link from the model, to avoid having disconnected links. 

During CopyLink2() both newfromnodedata and newtonodedata were null and I didn’t had the ValidUnconnectedLinks property of the model set explicitely (thus it was None). Now, having changed it to Allowed it works!!!

Thank you Walter for pointing me in the right direction!

Regards,
Marc

Hello Walter,

yesterday I was happy that the dragging of the node and the self-reference link worked after I had set the ValidUnconnectedLinks property to Allowed, but now I’m not happy with this solution anymore.

It’s because now, one is able to draw links with unconnected links, which in my case, is not allowed.

Now I’m wondering if I’m doing sth. wrong during drag & drop or if it either a bug or a Feature that one can olny drag links (at least self referencing links) when the ValidUnconnectedLinkspropert is set to Allowed.

I debugged a Little bit and the reason why I don’t see the link is that the CopyLink2() method has neither the newfromnodedata nor the newtonodedata set to sth. different from null and thus, according to the documentation, removed the link. But why are These two Parameters for the CopyLink2() method null? That’s the Point where I cannot get further. Do you perhaps some reason or sth. I might make wrong there?

Thanks in advance,
Marc

I was a bit surprised when you wanted to allow partly or fully disconnected links. But I don’t know your app.

Here is a slightly simplified definition of GraphLinksModel.CopyLink2:

    protected virtual void CopyLink2(LinkType oldlinkdata, CopyDictionary env, LinkType newlinkdata, NodeType newfromnodedata, NodeType newtonodedata, NodeType newlinklabel) {
      if (newfromnodedata != null) {
        ModifyLinkFromPort(newlinkdata, FindKeyForNode(newfromnodedata), FindFromParameterForLink(oldlinkdata));
      }
      if (newtonodedata != null) {
        ModifyLinkToPort(newlinkdata, FindKeyForNode(newtonodedata), FindToParameterForLink(oldlinkdata));
      }
      if (newlinklabel != null) {
        ModifyLinkLabelKey(newlinkdata, FindKeyForNode(newlinklabel));
      }
      if (this.ValidUnconnectedLinks == ValidUnconnectedLinks.None) {
        if (newfromnodedata == null || newtonodedata == null) {
          RemoveLink(newlinkdata);
        }
      }
    }

This is why I was asking about the nodes having the same keys that the link data has as references. For some reason GraphLinksModel.FindKeyForNode is returning null for the new node data. And that’s why I asked whether the GraphLinksModel had all of the same property values in both models.

Hi Walter,

you’re right. In first place, I don’t want to have unconnected links.

I just debugged again and made a Change in my link model classes, but with no success. Still, when the copyLink2 method is called. the newfromnodedata and newtonodedata are null. But I don’t think it has to do with the method FindKeyForNode you mentioned. I debugged into it and saw that it returns the correct key for the node. From what I can see in ReSharper, I think the Problem may be located somewhere in the following code snippet (see below). Either the method graphLinksModel1.GetFromNodeForLink or the method wy2.\u0023a.FindCopiedNode(toNodeForLink) may be responsible for passing null to the copyLink2 call, I think.

Do you perhaps have some idea how I could further track down this Problem?

If I don’t get this to work I’m thinking about trying a Workaround:

  • idea 1: allow unconnected links in the model but try to validate each link when it gets created or modified
  • idea 2: if idea1 doesn’t work, I could perhaps set the ValidUnconnectedLinks property temporarily to allowed for the drag&drop Operation and reset it to none when it has finished.

Kind regards,
Marc

if ((object) copiedLink != null)
{
NodeType fromNodeForLink = graphLinksModel1.GetFromNodeForLink(current);
// ISSUE: reference to a compiler-generated field
NodeType copiedNode1 = wy2.\u0023a.FindCopiedNode(fromNodeForLink);
NodeType toNodeForLink = graphLinksModel1.GetToNodeForLink(current);
// ISSUE: reference to a compiler-generated field
NodeType copiedNode2 = wy2.\u0023a.FindCopiedNode(toNodeForLink);
NodeType labelNodeForLink = graphLinksModel1.GetLabelNodeForLink(current);
// ISSUE: reference to a compiler-generated field
NodeType copiedNode3 = wy2.\u0023a.FindCopiedNode(labelNodeForLink);
// ISSUE: reference to a compiler-generated field
this.CopyLink2(current, wy2.\u0023a, copiedLink, copiedNode1, copiedNode2, copiedNode3);

Since it still isn’t clear to me, I’ll ask again:

Yes. LinkFromPath is set to “From” and LinkToPath is set to “To”. The other Parameters also look fine for me.

As I read your message, i.e. “isn’t doing what you want” it came to my mind that I could simple set the Parameters newfromnodedata and newtonodedata before forwarding the CopyLink2() method call to the base implementation. And it works now.

My link model has a reference to the backing Business model which knows about its predecessor and successor and thus I was able to get the node, e.g.

newfromnodedata = this.FindNodeByKey(newlinkdata.Predecessor.id);