Silverlight: Drag And Drop ListBoxItem to Canvas (using Telerik Control)


While surfing thru different forum I noticed that, lots of people are actually facing issues while trying to implement the drag and drop feature. The main problem arises while trying to drag from a ListBox to a panel like canvas. In this post, I will go thru the steps to demonstrate such feature.

Here I will use Telerik control to give out the demonstration. You can download the trial version of the dlls from Telerik Silverlight Control Page. I have implemented the demo using Silverlight 4 Beta 1. The same thing is also possible in earlier version of Silverlight. You can download Silverlight SDK from Silverlight Site. To develop apps in Silverlight 4 you must need Visual Studio 2010 Beta 2 which you can download from Microsoft site.

So, lets go for implementing the same. Create a Silverlight project. Lets create a ListBox and a Canvas inside the LayoutRoot:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <ListBox x:Name="lstBox" Margin="10" Grid.Column="0"/>
    <Canvas x:Name="cnvDropBox" Background="Yellow" Margin="10" Grid.Column="1"/>
</Grid>
Now in the code behind, we have to register the Drag and Drop events for the ListBox & Canvas. Use RadDragAndDropManager class to register the same. 
RadDragAndDropManager.AddDragInfoHandler(lstBox, OnDragInfo);
RadDragAndDropManager.AddDragQueryHandler(lstBox, OnDragQuery);
RadDragAndDropManager.AddDropInfoHandler(cnvDropBox, OnDropInfo);
RadDragAndDropManager.AddDropQueryHandler(cnvDropBox, OnDropQuery);

RadDragAndDropManager.SetAllowDrop(cnvDropBox, true);
The implementation of the events will be as below:
private void OnDragQuery(object sender, DragDropQueryEventArgs e)
{
    if (e.Options.Status == DragStatus.DragQuery)
    {
        var draggedListBoxItem = e.Options.Source as Image;
        e.Options.DragCue = draggedListBoxItem.Source;
        e.Options.Payload = draggedListBoxItem.Source;
    }

    e.QueryResult = true;
    e.Handled = true;
}
private void OnDragInfo(object sender, DragDropEventArgs e)
{
    if (e.Options.Status == DragStatus.DragComplete)
    {
        // comment this block if you are going to clone
        lstBox.Items.Remove(e.Options.Source);
    }
}
private void OnDropInfo(object sender, DragDropEventArgs e)
{
    var droppablePanel = e.Options.Destination;

    if (e.Options.Status == DragStatus.DropComplete && droppablePanel is Canvas)
    {
        FrameworkElement dragableControl = null;
        Point desiredPosition = new Point();
        Point currentDragPoint = e.Options.CurrentDragPoint;
        Point canvasPosition = cnvDropBox.TransformToVisual(null).Transform(new Point());

        if (e.Options.Source is Image)
        {
            // create the new instance & update the necessary properties
            // this step is require if you are going to make a clone
            Image tempDragableControl = e.Options.Source as Image;
            dragableControl = new Image() { Source = tempDragableControl.Source };
            cnvDropBox.Children.Add(dragableControl);
        }

        desiredPosition.X = currentDragPoint.X - canvasPosition.X;
        desiredPosition.Y = currentDragPoint.Y - canvasPosition.Y;
        dragableControl.SetValue(Canvas.LeftProperty, desiredPosition.X);
        dragableControl.SetValue(Canvas.TopProperty, desiredPosition.Y);
    }
}
private void OnDropQuery(object sender, DragDropQueryEventArgs e)
{
    var droppablePanel = e.Options.Destination;

    if (e.Options.Status == DragStatus.DropDestinationQuery && droppablePanel is Canvas)
    {
        e.QueryResult = true;
        e.Handled = true;
    }
}

As I am using Image inside the ListBoxItem, hence OnDragQuery I am setting the Source as an Image to the DragCue & PayLoad properties. OnDragInfo I am removing item from the ListBox. If you don’t want to remove the dragged image from the ListBox then just remove that line. OnDropInfo I am just placing the Image to the appropriate position which we will get as CurrentDragPoint in the DragDropEventArgs.

This is a sample demonstration. So, you have to explore it more to fulfil your requirement.

Download Sample Application:  Drag And Drop ListBoxItem to Canvas Demo


If you have come this far, it means that you liked what you are reading. Why not reach little more and connect with me directly on Twitter , Facebook , Google+ and LinkedIn . I would love to hear your thoughts and opinions on my articles directly. Also, don't forget to share your views and/or feedback in the comment section below.

17 comments

  1. Thanks for the example Kunal, however, when I comment the line as recommended for cloning

    // lstBox.Items.Remove(e.Options.Source);

    It stop working and gave me an error message (InvalidOperationException was unhandled by user code)
    on the following line
    ...
    cnvDropBox.Children.Add(dragableControl);
    ...

    Regards,

    Ridvan Aktas

    ReplyDelete
  2. actually it should not. but I will check it tonight again & will let you know.

    ReplyDelete
  3. Hey Ridvan,

    That was my mistake. You cannot directly do it out as the control is already present in the UI, so you cannot use the same reference as a child to the same. Hence the exception.

    So, just create a new instance of the image inside the OnDropInfo() & then add it to the UI.

    I have updated the sample app & the post with the same. Thanks for pointing it out.

    ReplyDelete
  4. Hi Kunal,

    Since all my images are listed in MainPage.xaml, I wonder how to tell my program to allow drag and drop only those images in each specific ListBox?
    Is there an easy way to implement this?
    Based on your code, you randomly lined images in the ListBox.

    private void PopulateListBox()
    {
    Random rnd = new Random();

    for (int i = 0; i < 20; i++)
    {
    Image draggableImage = new Image()
    {
    Source = new BitmapImage(new Uri("images/image_" + rnd.Next(1, 5) + ".jpg", UriKind.RelativeOrAbsolute))
    };

    RadDragAndDropManager.SetAllowDrag(draggableImage, true);
    lstBox.Items.Add(draggableImage);
    }
    }

    In the meantime, I download your other example (SL4RightClickContextMenuDemo) and will try to implement in my project as well. I hope you don’t mind. My goal is, once I complete Drag Drop an image on the Canvas, I can be able to write click and add IP address for pinging.

    Do you think that is also possible?

    Regards,

    Ridvan Aktas
    IT Services Manager, Americas

    Datamonitor Inc.
    245 5th Avenue, 4th Floor
    New York, NY 10016

    212-652-2646
    raktas@datamonitor.com

    ReplyDelete
  5. Ridvan, if you are adding the image in XAML, then also it is possible.

    First of all, add the reference of the Assembly by doing the following:

    xmlns:telerikControl="clr-namespace:Telerik.Windows.Controls.DragDrop;assembly=Telerik.Windows.Controls"

    Now, when you want to add the image just use AllowDrag to true. Your code will look like this:

    <Image telerikControl:RadDragAndDropManager.AllowDrag="True" />

    telerikControl:RadDragAndDropManager.AllowDrag="True" => will do the exact thing I did in my code behind:

    RadDragAndDropManager.SetAllowDrag(draggableImage, true);

    So, go ahead & implement it. Let me know if any issues.

    ReplyDelete
  6. Ahh, I didn't read your last update because I was busy changing the code. I guess it is OK, it works fine. I already post another question on the Silverlight.net but format was not good.
    Let me try it here.

    Hi Kunal,
    Thanks for posting wonderful help on your blog.
    I followed your idea of placing icons in the ListBox during the run time and I clean up the XAML partition of my project.
    Sniped

    PopulateHPServerListBox();
    RadDragAndDropManager.AddDragInfoHandler(HPServer, OnDragInfo);
    RadDragAndDropManager.AddDragQueryHandler(HPServer, OnDragQuery);
    RadDragAndDropManager.AddDropInfoHandler(DropArea, OnDropInfo);
    RadDragAndDropManager.AddDropQueryHandler(DropArea, OnDropQuery);
    RadDragAndDropManager.SetAllowDrop(DropArea, true);

    // HP Server ListBox will populate on Run Time
    private void PopulateHPServerListBox()
    {
    Image dragableHPServerLH3000R = new Image()
    {
    Source = new BitmapImage(new Uri("Images/hp_server/NetServerLH3000R.png ", UriKind.RelativeOrAbsolute))

    };

    RadDragAndDropManager.SetAllowDrag(dragableHPServerLH3000R, true);
    HPServer.Items.Add(dragableHPServerLH3000R);
    HPServer.Items.Add("HP NetServer LH3000R");

    }
    Full project located at http://cid-89e24e31b10a0ed6.skydrive.live.com/self.aspx/.Public/VisualLanSL4Beta12-3-09.rar
    For next step, I would like to know if there is a way to clean the Canvas if I would like to start Drag Drop new images from beginning. Like DOS’ CLR command.
    For second, I start looking into your other project “SL4RightClickContextMenuDemo” program. I would like to know if I can be able to attach that functionality to above code so I can be able to right click on each icon that I placed on the Canvas.
    By enabling right click on each icon, I can be able to select the option to enter a command (in this case “Enter an IP Address”).

    ReplyDelete
  7. The first query: Yes, you can clear the canvas using myCanvas.Children.Clear();

    The second query: Yes, you can also enable the right click behavior in your images to ask the user to enter IP address. Here follow the article & the next implementation logic is yours...

    ReplyDelete
  8. Hi Kunal,

    Was there supposed to be link to follow up?

    Ridvan

    ReplyDelete
  9. OK, first query was easy,
    Now it clears the Canvas.
    Second query seems a bit though :).

    private void clearScreen_Click(object sender, RoutedEventArgs e)
    {
    DropArea.Children.Clear();
    }

    ReplyDelete
  10. Hi Kunal,

    Can I have the article that you were mentioning on your previous post, I would like to follow up on it because I am stuck with implementing right click on my project.

    First:
    In your implementation, you are calling brdRightClickZone from C# during the run time. Since my icons have been cloned during the run time (not called from MainPage.XAML page), I wonder how can I be able to call them?

    brdRightClickZone.MouseRightButtonDown += new MouseButtonEventHandler(btnRightClick_MouseRightButtonDown);
    brdRightClickZone.MouseRightButtonUp += new MouseButtonEventHandler(brdRightClickZone_MouseRightButtonUp);

    Second:
    Can I be able to ping from Silverlight? There are not much information out there?
    I was thinking about creating another Silverlight page and call that page from right click menu.
    Will that possible?

    Regards,

    Ridvan

    ReplyDelete
  11. In your first query, as you are dropping the images by dragging into the drop panel, hence register the rightclick events on that. On the OnDropInfo() implementation after assigning a new instance of the image register the rightclick to it & in the implementation you can easily identify the rightclicked object from the sender.

    In your second query, what do you mean by ping?

    As per your third query, it is also possible.

    ReplyDelete
  12. Hi Kunal,

    I am a bit confused with OnDropInfo() implementation, I am afraid it may take a bit more time for me to overcome since I am a network guy rather than software developer and I never program anything until now. I am writing this program for my graduation assignment.

    Here are what I need to do to complete this project.
    1. Drag Drop icons to canvas - √ Done
    2. Right click icons and click "Enter IP" button. – In process
    3. Once IP address entered, program pings in the back ground.
    4. Depend on the Ping result, Red or Green light comes on next to icon. (Messages relied back with ICMP)
    5. Program continue pining in the background every 3 min to see if it is alive or dead.
    6. Adjust Red or Green light if computer stop responding ping.
    7. Save the locations and IP addresses of the each image on the canvas.
    8. Load previously saved locations – if needed.

    My goal of the project is create a visual network diagram that monitors servers, network printers, routers and switches to see if they are up or down.

    Well, I need to deliver all this by the 15th of this month. I hope I can complete all.

    Thanks for helping me on this project and answering my questions.

    Regards,

    Ridvan

    ReplyDelete
  13. Hi Kunal,

    I overcome the Drag & Drop and right click menu. My next challenges are implementing PING command when I click the "Enter" button after typing the IP address.

    Second challenge is how to insert Red and Green images(indicators) to Cloned images on the Canvas when ICMP (PING Results) return results.

    Regards,

    Ridvan

    ReplyDelete
  14. Hi Kunal,

    I placed cloned image on canvas to listbox and added Red and Green images to the list box.

    When I get successful, it add Green image to listbox and when it fail, it will add Red images to listBox.

    Now, remaining problem is how to get PING sucessful and PING failed.

    Regards,

    Ridvan

    ReplyDelete
  15. Hi Kunal,

    I implemented double click version of the same project rather than right click. It seems both do the same but a bit less coding.
    I also did this on my SL3 version of the code.

    http://cid-89e24e31b10a0ed6.skydrive.live.com/self.aspx/.Public/VisualLanMapV2.rar

    Regards,

    Ridvan

    ReplyDelete
  16. This comment has been removed by the author.

    ReplyDelete


 
© 2008-2016 Kunal-Chowdhury.com - Microsoft Technology Blog for developers and consumers | Designed by Kunal Chowdhury
Back to top