DragDropPayloadManager
The DragDropPayloadManager lets you easily generate valid drag payload objects that can be used in various drag-and-drop scenarios.
This article will cover the main features of the DragDropPayloadManager as well as their usage within a sample drag-and-drop example between two RadListBoxes.
Using the DragDropPayloadManager
Along with the option to easily create a valid drag payload, the DragDropPayloadManager allows you to attach a DataConverter to it. This DataConverter will be carried within the different methods and used in order to convert the DataObjects from one to another type. This section will demonstrate the exact approach for creating a payload, attaching a DataConverter and using it.
Let's start by creating a simple drag drop application with two RadListBoxes with ItemsSources of different types. You have the following ViewModel with one collection that contains custom objects of type Customer and another with an empty collection of strings:
public class ViewModel : ViewModelBase
{
public ObservableCollection<Customer> ItemsSource1 { get; set; }
public ObservableCollection<string> ItemsSource2 { get; set; }
public ViewModel()
{
this.ItemsSource1 = new ObservableCollection<Customer>
{
new Customer { FirstName= "John", LastName = "Smith", Age = 24},
new Customer { FirstName= "George", LastName = "Lucas", Age = 35},
new Customer { FirstName= "Justin", LastName = "Marks", Age = 16},
new Customer { FirstName= "Emily", LastName = "Rose", Age = 40},
new Customer { FirstName= "Mike", LastName = "Jones", Age = 20},
};
this.ItemsSource2 = new ObservableCollection<string>();
}
}
<Grid>
<Grid.DataContext>
<local:ViewModel />
</Grid.DataContext>
<Grid.Resources>
<Style TargetType="telerik:RadListBoxItem">
<Setter Property="telerik:DragDropManager.AllowCapturedDrag" Value="True" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<telerik:RadListBox x:Name="ListBox1" Grid.Column="0" Margin="10"
ItemsSource="{Binding ItemsSource1}"
DisplayMemberPath="FirstName"
AllowDrop="True" />
<telerik:RadListBox x:Name="ListBox2" Grid.Column="1" Margin="10"
ItemsSource="{Binding ItemsSource2}"
AllowDrop="True" />
</Grid>
Figure 1: ListBox1 is on the left and ListBox2 is on the right.
Next you will need to enable the drag and drop by adding a DragInitializeHandler for the first RadListBox, so you can drag from the first RadListBox and drop afterwards on the second one.
DragDropManager.AddDragInitializeHandler(this.ListBox1, OnDragInitialize);
public class CustomerToStringConverter : DataConverter
{
public override object ConvertTo(object data, string format)
{
if (format == typeof(string).FullName && DataObjectHelper.GetDataPresent(data, "DragData", false))
{
var customer = DataObjectHelper.GetData(data, "DragData", false) as Customer;
var fullInfoString = "Name: " + customer.FirstName + " " + customer.LastName + ", Age: " + customer.Age;
return fullInfoString;
}
return null;
}
public override string[] GetConvertToFormats()
{
return new string[] { typeof(string).FullName };
}
}
The DataConverter can convert objects from multiple types to multiple types inside its ConvertTo() method. You will need to check if the format is the desired one as well as if the needed data is present. The GetConvertToFormats() method should return a collection of the supported formats to convert to, so the control can accept or prevent the drop when the dragged object cannot be converted to the required format.
In the DragInitialize handler itself you will need to pass to the DragDropPayloadManager an instance of the converter that will be carried by the payload within the events and used when needed:
private void OnDragInitialize(object sender, DragInitializeEventArgs e)
{
e.AllowedEffects = DragDropEffects.All;
var payload = DragDropPayloadManager.GeneratePayload(new CustomerToStringConverter());
var data = ((FrameworkElement)e.OriginalSource).DataContext;
payload.SetData("DragData", data);
e.Data = payload;
e.Handled = true;
}
DragDropManager.AddDropHandler(this.ListBox2, OnDrop);
private void OnDrop(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
{
var data = DragDropPayloadManager.GetDataFromObject(e.Data, typeof(string).FullName);
((IList)(sender as RadListBox).ItemsSource).Add(data);
DragDropPayloadManager.SetData(e.Data, "IsDropSuccessful", true);
e.Handled = true;
}
DragDropManager.AddDragDropCompletedHandler(this.ListBox2, OnDragDropCompleted);
private void OnDragDropCompleted(object sender, DragDropCompletedEventArgs e)
{
var isDropSuccessful = DragDropPayloadManager.GetDataFromObject(e.Data, "IsDropSuccessful");
if (isDropSuccessful != null && (bool)isDropSuccessful)
{
var data = DragDropPayloadManager.GetDataFromObject(e.Data, "DragData");
((IList)(sender as RadListBox).ItemsSource).Remove(data);
}
e.Handled = true;
}
DragDropManager.AddDragOverHandler(this.ListBox2, OnDragOver);
private void OnDragOver(object sender, Telerik.Windows.DragDrop.DragEventArgs e)
{
var formats = DragDropPayloadManager.GetFormats(e.Data, true);
if (formats.Contains(typeof(string).FullName))
{
e.Effects = DragDropEffects.Move;
}
else
{
e.Effects = DragDropEffects.None;
}
e.Handled = true;
}
Figure 2: ListBox1 is on the left and ListBox2 is on the right. After the drop is completed the object is converted to string.
Find a runnable project of the previous example in the WPF Samples GitHub repository.