Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Silverlight Drag and Drop for Business Applications

0.00/5 (No votes)
15 Jun 2011 1  
This article covers the mechanics of how to use Silverlight drag and drop in a business application.

Example Screen

Introduction

In the development of business websites, we have encountered some hurdles in the use of Silverlight, in particular using the drag and drop functionality that was not easily solved by a quick search of the internet. There are many examples of using Silverlight drag and drop with file system utilities, but how does it work if you want to have drag and drop in your business application where the objects come from your database instead of a file system? All the examples we found ignore the need for a business application to know exactly what moved and from where and the need to update the database with the information that changed.

This article presents the solution we came up with to solve the problem of knowing which object was moved and details about that object. Due to the extensive functionality of Silverlight, there are probably other ways to solve this problem.

Background

This article assumes at least some familiarity with Silverlight, particularly version 4, and C#.

What's necessary to set up dynamic drag and drop

The technique we used is fairly simple as far as representing the objects is concerned. A ListBox forms the main container, and ListBoxItems are used to display the business objects. Since we need a little flexibility to display additional information, such as the headings as well as enabling the drag and drop functionality, there are a few things that must also be included. To handle this, we used a StackPanel as our column container, with its first child being the heading for the column, followed by the ListBoxDragDropTarget which in turn contains the ListBox. So with this hierarchy of containers, the visual drag and drop functionality already works, meaning that you can drag from one column and drop it into another column with no additional code. The limitation here is that the database does not get updated with this change.

Creating this hierarchy takes surprisingly little code, and results in a model that is completely dynamic, meaning that you can have as many columns and items in each column as you want. The XAML is fairly short, and is as follows:

<Grid x:Name="LayoutRoot" Background="White">
    <TextBlock Margin="20,0,0,0" HorizontalAlignment="Left" 
       VerticalAlignment="Top" Text="Silverlight Business Drag and Drop" 
       FontSize="16"/>
    <Grid x:Name="DragDropRoot" HorizontalAlignment="Stretch" 
       VerticalAlignment="Stretch" Margin="40,40,0,0"/>
</Grid>

Since all the remaining work was done from code, the columns and items in code are a little more involved than would be in XAML, since you need to make sure all the properties are set so that the visuals look correct.

Let's start by building the columns themselves. Using the above mentioned hierarchy, we start with StackPanels, and add a column header to indicate to the user the purpose of the column. Creating the ListBoxDragDropTarget is only three lines of code, then you add a ListBox to actually house the items.

// Column Parent
StackPanel column1 = new StackPanel();
column1.Margin = new Thickness(0, 0, 0, 0);
column1.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
column1.VerticalAlignment = System.Windows.VerticalAlignment.Top;
column1.Width = 150;
column1.Height = 400;

// Column Heading
TextBlock hdr1 = new TextBlock();
hdr1.Text = "Column 1";
hdr1.Height = 30;
hdr1.Margin = new Thickness(0, 0, 0, 0);
hdr1.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
hdr1.VerticalAlignment = System.Windows.VerticalAlignment.Top;

// Enabling Drag and Drop
ListBoxDragDropTarget source = new ListBoxDragDropTarget();
source.Drop += new Microsoft.Windows.DragEventHandler(dest_Drop);
source.AllowDrop = true;

// Setting up the Parent of the items that can be dragged and dropped
ListBox box1 = new ListBox();
box1.Name = "Column1";
box1.Margin = new Thickness(1, 1, 0, 0);
box1.Background = new SolidColorBrush(Colors.Transparent);
box1.FlowDirection = System.Windows.FlowDirection.LeftToRight;
box1.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
box1.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
box1.Width = 140;
box1.Height = 360;

// Heirarchy of Items
s1.Children.Add(txt1);
i1.Content = s1;
// Items within this column are added here
box1.Items.Add(i1);
column1.Children.Add(hdr1);
source.Content = box1;
column1.Children.Add(source);
DragDropRoot.Children.Add(column1);

Note: at the bottom of the above code segment, the hierarchy is built so that the objects all work correctly.

After the background is set up for a column, the column is still empty as far as items to be able to demonstrate it. Though I only show two columns in this demo, it is certainly feasible to have any number of columns that your application may need.

Since business objects (including both the columns and the items within each column) come from a database and usually would have a unique identifier for each, we can use that unique identifier as part of the name for each item. In the following example, we see how to build the individual items, such that it can be done for any number of items. Each ListBoxItem represents a business object, so the Name associated with the ListBoxItem could contain your unique identifier, or a name plus an identifier if you are representing multiple objects, to ensure that you can recognize it when it is dropped on another column.

Within each ListBoxItem, you will generally have multiple items to show that each help describes this item. For that reason, I generally use a StackPanel (or Grid) which then contains each of the items that will be shown in the user interface. Within the StackPanel, you might have TextBlocks like I demonstrate here, or any number of other objects (images, buttons, etc.) that make the user view complete.

The final three lines of code are used to collect all the items together into a package that can be added to the column defined above.

ListBoxItem i2 = new ListBoxItem();
i2.BorderBrush = new SolidColorBrush(Colors.Red);
i2.BorderThickness = new Thickness(1);
i2.Name = "2";
// This would be your unique key so that you can recognize
// the item when it is dropped on another column

StackPanel s2 = new StackPanel();
s2.Background = new SolidColorBrush(Colors.Magenta);
s2.Width = 130;
s2.Height = 100;
s2.FlowDirection = System.Windows.FlowDirection.LeftToRight;

TextBlock txt2 = new TextBlock();
txt2.Width = 129;
txt2.Height = 90;
txt2.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
txt2.VerticalAlignment = System.Windows.VerticalAlignment.Top;
txt2.TextWrapping = TextWrapping.Wrap;
txt2.Text = "This is another source item that can be dragged and dropped";

// Add other Controls as needed to the StackPanel

s1.Children.Add(txt1);
i1.Content = s1;
box1.Items.Add(i1);

That defines the columns and the items for those columns. What comes next is the code required to recognize the actions taken in the drag and drop. While this is only a few lines of code, because of the extraction of data from the complex parameter passed in, it is not obvious how you get the name of the item from the DragEventArgs parameter. By extracting both column names as well as the name of the item that was moved, you should have complete details to be able to update your database or apply any rules that may be necessary.

void dest_Drop(object sender, Microsoft.Windows.DragEventArgs e)
{
    var format = e.Data.GetFormats()[0];
    ItemDragEventArgs dragItem = e.Data.GetData(format) as ItemDragEventArgs;

    bs = (ListBox)dragItem.DragSource;
    ListBoxDragDropTarget b = (ListBoxDragDropTarget)sender;
    bd = (ListBox)b.Content;

    string WhoWasIt = ((ListBoxItem)bs.SelectedItem).Name;
    MessageBox.Show("Item " + WhoWasIt + " was moved from " + 
                    bs.Name + " to " + bd.Name);
}

The first two lines above extract the object being dragged, including where it came from. From that, the middle three lines give you the DragSource as the source object and the sender's Content as the destination object. Once you have that, you can pick up the SelectedItem as the ListBoxItem being dragged and extract the name to get your business object's unique code (the WhoWasIt variable above shows the original name of the object). With that information, you can then update your database with the information that the object was moved from one column to another column. If you also need the resulting order, you will need to add a StoryBoard event to give this event time to complete so that you can look through the destination ListBox to find out where in the ListBox the item ended up. Given that you already have the object name, it is easy to find in the destination ListBox.

If you require multiple item drag and drop, you would then step through the SelectedItems collection instead of using the SelectedItem (which will only give you the first item if you drag multiple items).

Using the code

To use this code, you will need to consider a few things, such as what information from your database will be used to generate each ListBoxItem, then what information will be needed to update your database with the results of the drag and drop operation. Since this example does not include database access code, or the loops you will need to build multiple objects, you will need to wrap at least the item creation in a loop, and perhaps the column creation as well if there are a number of columns.

Points of interest

It might be hard to find the information you need from Silverlight, but once you have found it, it is easy to accomplish many of the tough problems in only a few lines of code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here