New to Telerik UI for WinFormsStart a free 30-day trial

Modify the DragDropService behavior

Updated over 6 months ago

This article demonstrates how to customize the TreeViewDragDropService behavior and more precisely how to customize it to copy the nodes when dropped, instead of moving them.

WinForms RadTreeView Modify the DragDropService behavior

To achieve this scenario we will need to create a descendant of TreeViewDragDropService (lets call it CustomDragDropService) where we will expose the RadTreeViewElement as a field, so we can use it later. This field will be assigned in the CustomDragDropService class constructor. We will also need another field of type RadTreeNode which will hold the dragged node. The latter will be assigned in the PerformStart and will be cleared in the PerformStop method.

Next we need to override the OnPreviewDragOver method, where we will specify upon what conditions a drop will be allowed and finally, in the OnPreviewDragDrop method override, we will add the logic for copying the selected nodes instead of moving them:

C#
class CustomDragDropService : TreeViewDragDropService
{
    RadTreeViewElement owner;
    RadTreeNode draggedNode;
    //Initialize the service
    public CustomDragDropService(RadTreeViewElement owner)
        : base(owner)
    {
        this.owner = owner;
    }
    //Save the dragged node
    protected override void PerformStart()
    {
        base.PerformStart();
        TreeNodeElement draggedNodeElement = this.Context as TreeNodeElement;
        this.draggedNode = draggedNodeElement.Data;
    }
    //Clean the saved node
    protected override void PerformStop()
    {
        base.PerformStop();
        this.draggedNode = null;
    }
    //If tree element is hovered, allow drop
    protected override void OnPreviewDragOver(RadDragOverEventArgs e)
    {
        base.OnPreviewDragOver(e);
        RadTreeViewElement targetElement = e.HitTarget as RadTreeViewElement;
        if (targetElement != null && targetElement != this.owner)
        {
            e.CanDrop = true;
        }
    }
    //Create copies of the selected node(s) and add them to the hovered node/tree
    protected override void OnPreviewDragDrop(RadDropEventArgs e)
    {
        TreeNodeElement targetNodeElement = e.HitTarget as TreeNodeElement;
        RadTreeViewElement targetTreeView = targetNodeElement == null ? e.HitTarget as RadTreeViewElement : targetNodeElement.TreeViewElement;
        if (targetTreeView == this.owner)
        {
            base.OnPreviewDragDrop(e);
            return;
        }
        if (targetTreeView == null)
        {
            return;
        }
        List<RadTreeNode> draggedNodes = this.GetDraggedNodes(draggedNode);
        targetTreeView.BeginUpdate();
        this.owner.BeginUpdate();
        bool copyNodes = this.IsCopyingNodes;
        foreach (RadTreeNode node in draggedNodes)
        {
            RadTreeNode newNode = CreateNewTreeNode(node);
            if (targetNodeElement != null)
            {
                targetNodeElement.Data.Nodes.Add(newNode);
            }
            else
            {
                targetTreeView.Nodes.Add(newNode);
            }
        }
        this.owner.EndUpdate();
        targetTreeView.EndUpdate();
    }
    //Return a copy of a node
    protected virtual RadTreeNode CreateNewTreeNode(RadTreeNode node)
    {
        return node.Clone() as RadTreeNode;
    }
}

After the custom drag and drop behavior is created, we need to replace the default one. This can be achieved in the CreateDragDropService method of RadTreeViewElement, so we create a new element for the purpose:

C#
class CustomTreeViewElement : RadTreeViewElement
{
    //Enable themeing for the element
    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(RadTreeViewElement);
        }
    }
    //Replace the default drag drop service with the custom one
    protected override TreeViewDragDropService CreateDragDropService()
    {
        return new CustomDragDropService(this);
    }
}

Now we need to use this CustomTreeViewElement in the tree. To do that we need to pass a new instance of this element in the CreateTreeViewElement method of RadTreeView descendant:

C#
class CustomTreeView : RadTreeView
{
    //Replace the default element with the custom one
    protected override RadTreeViewElement CreateTreeViewElement()
    {
        return new CustomTreeViewElement();
    }
    //Enable theming for the control
    public override string ThemeClassName
    {
        get
        {
            return typeof(RadTreeView).FullName;
        }
    }
}

Finally, lets populate the tree and test the new behavior:

C#
customTreeView1.AllowDragDrop = true;
customTreeView1.MultiSelect = true;
customTreeView2.AllowDragDrop = true;
customTreeView2.MultiSelect = true;
for (int i = 0; i < 10; i++)
{
    customTreeView1.Nodes.Add("First tree node " + i);
    customTreeView2.Nodes.Add("Second tree node " + i);
}

The result can be observed at the screen shot at the top.

See Also

In this article
See Also
Not finding the help you need?
Contact Support