I have a situation where I have 2 XamDataTrees that I need to be able to drag and drop items from one to the other.
Data structure consists of Schemas, Groups, Nodes, Leaves:
What we want to achieve with dragging:
Since the tree is particular about the type when dragging and dropping, this is proving to be a challenging problem. Deriving from a base type gets things working, but I can't disallow things like dragging a node from Tree 2 into a schema in Tree 1. This seems to be a problem of the IsDropTarget being conditional on what the drag source type is and I can't figure out how to make that happen with this control. Any help would be appreciated.
Hello Tracie,
I have been investigating into your requirement, and at the moment, none of the drag-drop related events that the XamDataTree exposes will really let you restrict drag and drop from one node to another, especially if they are all derived from a base type and the collections that make up your layout are child collections of that base type as you have mentioned.
With that said, some time ago I did derive a solution for another forum thread discussion using the IsEnabledMemberPath of the NodeLayout and the NodeDraggingStart and NodeDragEnd events so that you can disable certain underlying data items from being dragged to depending on the type that you are currently dragging. That forum thread, along with a sample project I wrote for it is located here: https://es.infragistics.com/community/forums/f/retired-products-and-controls/105253/xamdatatree-drag-drop-within-the-parent-node. Please disregard the mentioning of the “Silverlight” XamDataTree, as the XamDataTree was a shared control between Silverlight and WPF, back when we still supported Silverlight.
By setting the underlying property that the IsEnabledMemberPath is pointed at such that some nodes will be disabled, your end user will not be able to drag to the nodes that are disabled. The same can be said from Tree 1 to Tree 2 in this case if you mark the IsEnabledMemberPath for all of the items in Tree 2 to be disabled when a node begins dragging in Tree 1. Then, you can reset the underlying IsEnabledMemberPath property in the NodeDragEnd event.
I hope this helps you. Please let me know if you have any other questions or concerns on this matter.
Hi Andrew,
Thanks for the reply.
The thread that you pointed me to isn't terribly helpful because the NodeDraggingStart event doesn't appear to know at any point what the droptarget will be. What I really need is the ability to disable the droptarget dependent on the types for both the dragsource and the droptarget.
With that said, I was able to get something kind of working through the NodeDragDrop event. I look for the type on both the dragnode and the droptarget, then set
e.DragDropEventArgs.OperationType = Infragistics.DragDrop.OperationType.DropNotAllowed; e.Handled = true;
This seems to work, the only issue at this point is the styling of the cursor as it hovers over the droptarget. It indicates that a drop should be possible, but this logic disables it. Any clues on how I can restyle the template?
Excellent, this was kind of the direction that I was heading in. I think the one question that I have is whether you would recommend using the IsEnabled pattern to enable/disable each item, or if directly manipulating the IsDropTarget property will work just as well? In my limited testing it seems to work well, but I am unclear if there are downsides to directly manipulating the control like that.
I believe that both the IsEnabled pattern and the IsDropTarget will work equally as well with respect to the ability to drag the node to another tree or another node. The reason that I had originally recommended usage of IsEnabled though, is because that will “grey out” the nodes that cannot be dragged to as well as preventing the actual drag and modifying the cursor when you drag over it. The IsDropTarget will only change the cursor.
In my personal opinion, the IsEnabled bit is a bit more user-friendly as it provides an extra layer of being able to see where you can drag to, but the actual functionality is essentially the same either way.
Please let me know if you have any other questions or concerns on this matter.
Andrew thanks so much, this has been very helpful. One more thing that may complete the picture.
When iterating through the nodes collection, is there a way to know what the parent node is at any given point? The IsEnabled path is not working for me because of the common base type that I have to use, so doing this in the viewmodel (while it would be ideal) doesn't appear to be an option. Can you advise a way to traverse back up the tree if needed?
Traversing down is not a problem given that every node has a nodescollection that makes the recursive piece down through the tree pretty easy.
Or....would it be possible to bind IsDropTarget on the NodeLayout to a property on the viewmodel? (I've tried this with no success.) That would be ideal, but I'm thinking you might have suggested it if it were possible.
Thank you for your update on this matter.
In order to access the parent node from a child XamDataTreeNode, I would recommend using the node.Manager.ParentNode property path. If the current “node” has a ParentNode, this will return it, else it will return null.
Regarding binding the IsDropTarget to the NodeLayout, I do not believe this would be an option if you are using the common base type. The value of that IsDropTarget will blanket onto every node in that particular NodeLayout. Furthermore, the NodeLayout object is not actually a visual element in WPF, and so binding the properties there might be a bit complicated. You would likely need to do a RelativeSource Self binding to get the Tree from the NodeLayout and then use its DataContext in order to bind its properties.
I posted this earlier, but it didn't seem to take.
I've got this mostly working. I ended up not using either pattern of setting IsDropTarget or IsEnabled because it seemed to completely block the ability to reorder items within one of the child collections. I've come up with a type structure that leverages how the tree allows or disallows dragging based on types, and it works the way we need in almost all cases laid out in my first post. Here is how it is set up:
Schema, has one ObservableCollection<Group>Group : GroupingItem, has one ObservableCollection<GroupingItem>Device : GroupingItemSchemaNode : GroupingItem
There are 2 issues:
I have a sample of my project, but can't seem to attach it. I'll try in a separate post.
EDIT: Is there a way to upload a sample? It doesn't seem to let me.
Great thanks for the follow up. Would it be possible to get an idea for how quickly a fix for this would be released?
Also, could you give us a stable workaround? What I've got for a workaround doesn't work very well.
After a bit more investigation into this behavior, I do believe this is a bug in the XamDataTree control. It appears that we are caching a specific type for each “level” of nodes that corresponds to the underlying collection type. We are using that specific collection type when determining whether or not you can drag to other nodes, and so we are evaluating whether or not the Type Group is the same as the Type GroupingItem here, and if not, you will not be able to drag.
This is unexpected behavior, and as such I have asked our engineering teams to examine it further. To ensure it will receive attention, I have logged it in our internal tracking systems with a development ID of 273599. I will be linking this to a private support case so that you can be notified when a fix or other resolution is found. This support case has an ID of C-00220300 and you can access it after signing into your Infragistics account on the website here: https://account.infragistics.com/support-cases.
Right, so changing the child collection type in the Schema from ObservableCollection<Group> to ObservableCollection<GroupingItem> is a problem because then the tree allows Devices and SchemaNodes to be placed in that within Schemas, something that I'm trying to disallow. Only Groups should be allowed within a Schema's children, which was why that structure is set up that way.
Is this a bug within the tree then? It seems that what I want to do with this data structure should be possible, but it just won't allow the placement of a group within a group's children.
I have been investigating into the sample project you have provided, and it seems that the underlying reason for the issues that you are seeing is due to the Schema class’s Children collection being an ObservableCollection<Group> rather than an ObservableCollection<GroupingItem>. I am unsure if this is an option for you to change as it may break your data structure, but doing so appears to resolve the drag and drop issues you are seeing.
This is rather strange, as the Group class derives from GroupingItem, and that leads me to believe that perhaps internally we are doing something incorrectly and are potentially not checking for base-types when evaluating a drag and drop operation. I am currently researching this a bit more to see if this is the indeed the case, and I am attaching a modified sample project to demonstrate this change working.
0652.GroupEditorPrototype.zip
That seemed to work. The drag/drop from the right tree to the left seems to work well. What I'm concerned with is the dragging within the left tree, specifically dragging a group into a group within that tree.