Announcement

All important changes of my site and my blog will be announced here.

Computer security

This is my hobby. I spend my freetime for it. I am not professional in this area. But I like it very much.

Everything Else

Which doesn’t belong to other categories will land here. It maybe about my daily life, entertainment, music, game … or something like that

Programming

This is my job. That means everyday I must sit before the monitor. Tip something, be annoyed by bugs,… but I simply like it.

Tutorial

When I found something interesting, I would like to share it to everyone. That is the reason for this category comes.

Home » Programming

Silverlight, WPF – ListBox Drag and Drop

Submitted by on Sunday, 28 February 2010No Comment | 2,425 views

During my development I need to implement the drag and drop feature in Silverlight. It’s pretty easy to make this feature work in Windows Form but it’s not simple to enable this feature on control in Silverlight. Therefore the developer team of Silverlight has developed a Silverlight toolkit to help us to alleviate our work. The Silverlight Toolkit is a collection of Silverlight controls, components and utilities made available outside the normal Silverlight release cycle. For more details about this toolkit you can read here http://silverlight.codeplex.com/.
In this example I would like to illustrate how we can use this toolkit to adapt the drag and drop to list box component of Silverlight. First you need to browse to URL above and install Silverlight Toolkit, then use Microsoft Expression Blend to add two list boxes to our application

<UserControl x:Class="SVL_Drag_and_Drop.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="452" d:DesignHeight="372">
  <Grid x:Name="LayoutRoot">
  	<StackPanel Margin="8" Orientation="Horizontal">
		<ListBox x:Name="lstbFrom" Width="219" Height="500" DisplayMemberPath="FullName">
		</ListBox>
		<ListBox x:Name="lstbTo" Width="217" Height="500" DisplayMemberPath="FullName"/>
  	</StackPanel>
  </Grid>
</UserControl>

The DisplayMemberPath is data bound with property FullName of data source. Our data source is simply a list of students with their first and last name.

public static ObservableCollection<StudentDetails> GetListOfStudent()
{
	ObservableCollection<StudentDetails> lstSD = new ObservableCollection<StudentDetails>();
	for (int nIndex = 0; nIndex < 10; nIndex++)
	{
		StudentDetails sdDetails = new StudentDetails() { FirstName = "First: " + RandomString(8, true), LastName = " Last: " + RandomString(8, true) };
		lstSD.Add(sdDetails);
	}
	return lstSD;
}
public class StudentDetails
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public string FullName
	{
		get { return (FirstName + LastName); }
	}
}

We load data source into list box From when application is loaded

public partial class MainPage : UserControl
{
	public MainPage()
	{
		InitializeComponent();
		Loaded += new RoutedEventHandler(MainPage_Loaded);
	}
	void MainPage_Loaded(object sender, RoutedEventArgs e)
	{
		lstbFrom.ItemsSource = Students.GetListOfStudent();
	}
}

When we run our application, we’ll see list of student in list box From but we still cannot drag and drop items between list box. To adapt this feature, first let’s add reference to System.Windows.Controls.Toolkit, add toolkit:ListBoxDragDropTarget attribute to activate drag feature and mswindows:DragDrop.AllowDrop=”True” to allow drop

<Grid x:Name="LayoutRoot">
  	<StackPanel Margin="8" Orientation="Horizontal">
        <toolkit:ListBoxDragDropTarget mswindows:DragDrop.AllowDrop="True">
            <ListBox x:Name="lstbFrom" Width="219" Height="500" DisplayMemberPath="FullName">
            </ListBox>
        </toolkit:ListBoxDragDropTarget>
        <toolkit:ListBoxDragDropTarget mswindows:DragDrop.AllowDrop="True">
            <ListBox x:Name="lstbTo" Width="217" Height="500" DisplayMemberPath="FullName"/>
        </toolkit:ListBoxDragDropTarget>
  	</StackPanel>
</Grid>

After adding these attributes to list box, compile, we can drag and drop items between list boxes. If you want to move items within a list box, you can use StackPanel as ItemTemplate

<Grid x:Name="LayoutRoot">
  	<StackPanel Margin="8" Orientation="Horizontal">
        <toolkit:ListBoxDragDropTarget mswindows:DragDrop.AllowDrop="True">
            <ListBox x:Name="lstbFrom" Width="219" Height="500" DisplayMemberPath="FullName">
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel/>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
            </ListBox>
        </toolkit:ListBoxDragDropTarget>
        <toolkit:ListBoxDragDropTarget mswindows:DragDrop.AllowDrop="True">
            <ListBox x:Name="lstbTo" Width="217" Height="500" DisplayMemberPath="FullName"/>
        </toolkit:ListBoxDragDropTarget>
  	</StackPanel>
</Grid>

The complete source code you can download here “SVL Drag and Drop”.

UPDATE 05.11.2011

For WPF there is unfortunately no toolkit helping us to solve Drag and Drop reasonably. We must implement this feature ourselves. Create new project of WPF and insert a StackPanel with 2 list boxes as below

<StackPanel Margin="8" Orientation="Horizontal">
	<ListBox x:Name="lstbFrom" Width="219" Height="500" DisplayMemberPath="FullName" PreviewMouseLeftButtonDown="lstbFrom_PreviewMouseLeftButtonDown" PreviewMouseMove="lstbFrom_PreviewMouseMove" SelectionMode="Multiple"  >
	</ListBox>
	<ListBox x:Name="lstbTo" Width="217" Height="500" DisplayMemberPath="FullName" Drop="lstbTo_Drop" DragEnter="lstbTo_DragEnter" AllowDrop="True"/>
</StackPanel>

Because we have no clues to know if a Drag Action is taking place, we must calculate the difference of mouse position to see if it is greater than a threshold. When it is above the threshold, we make a call to DoDragDrop with appropriate data

private void lstbFrom_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
	startPoint = e.GetPosition(null);
}
private void lstbFrom_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
	// Get the current mouse position
	Point mousePos = e.GetPosition(null);
	Vector diff = startPoint - mousePos;
	if (e.LeftButton == MouseButtonState.Pressed &&
		(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
		Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
	{
		DataObject dragData = new DataObject(DataObjectFormat, (sender as ListBox).SelectedItems.Cast<StudentDetails>().ToList());
		DragDrop.DoDragDrop(sender as ListBox, dragData, DragDropEffects.Move);
	}
}

As you can see, I wrap our data into DataObject and sent it to receiver. At the receiver, we extract the data back from DataObject, insert it into destination and remove it from source.

private void lstbTo_Drop(object sender, DragEventArgs e)
{
	if (e.Data.GetDataPresent(DataObjectFormat))
	{
		foreach (StudentDetails contact in (e.Data.GetData(DataObjectFormat) as List<StudentDetails>))
		{
			if ((e.Effects & DragDropEffects.Move) == DragDropEffects.Move)
				((IList)lstbFrom.ItemsSource).Remove(contact);
			(sender as ListBox).Items.Add(contact);
		}
	}
}
private void lstbTo_DragEnter(object sender, DragEventArgs e)
{
	if (!e.Data.GetDataPresent(DataObjectFormat) ||
sender == e.Source)
	{
		e.Effects = DragDropEffects.None;
	}
}

The demo source you can download at “WPF ListBox MultiSelect Drag And Drop

Popularity: 4% [?]

My strongly recommended books to read. Choose one and enjoy yourself.

Related Posts:

  • No Related Posts

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.