|
|
        Telerik Drag & Drop model for WPF allows users to drag any element and drop it onto another element. The associated events allow users to completely handle the Drag & Drop process, thus easily building complex and flexible business logic. The Drag and Drop Manager allows Drag-Drop operations to be implemented between any two controls. The manager can generate visual cues to help the user and will automatically scroll ScrollViewers to reveal content. Note |
|---|
In order to use the RadDragAndDropManager, you should add a reference to the Telerik.Windows.Controls.dll assembly. |
Allowing Drag and Drop
Before using RadDragAndDropManager for implementing drag and drop functionality, you need to be aware of several things: - The first step is to import the appropriate namespace in XAML:
CopyXAML xmlns:telerikDragDrop="clr-namespace:Telerik.Windows.Controls.DragDrop;assembly=Telerik.Windows.Controls" - Every object that will be dragged must have the AllowDrag property set to True. This is an attached property and in XAML it can be set in the following way:
CopyXAML <Rectangle x:Name="rectangle" telerikDragDrop:RadDragAndDropManager.AllowDrag="True"/> In the code-behind the AllowDrag property should be set like this: CopyC# RadDragAndDropManager.SetAllowDrag( rectangle, true ); CopyVB.NET RadDragAndDropManager.SetAllowDrag(rectangle, True) - Similarly, you need to set the AllowDrop property to True for all the objects that will be the end destination (drop targets) for the drag/drop operation. This would enable the RadDragAndDropManager to recognize and consider these objects.
CopyXAML <ListBox x:Name="listBox" telerikDragDrop:RadDragAndDropManager.AllowDrop="True"/> CopyC# RadDragAndDropManager.SetAllowDrop( listBox, true ); CopyVB.NET RadDragAndDropManager.SetAllowDrop(listBox, True) Note |
|---|
The "telerikDragDrop" alias refers to the Telerik.Windows.Controls.DragDrop namespace in the Telerik.Windows.Controls.dll assembly. |
Once the Drag/Drop operation is allowed, various drag and drop scenarios can be implemented using the RadDragAndDropManager. Check out the Drag and Drop Scenarios topic to see the most common. Drag and Drop Demo
The following example demonstrates how to implement simple drag and drop between two ListBox controls. - Open VisualStudio and create a new project.
- For the purpose of this demo, you need to add a new class named ApplicationInfo to the project. Both of the ListBox controls will be data bound to a collection of ApplicationInfo objects.
CopyC# public class ApplicationInfo
{
public ApplicationInfo( string iconPath, string name, string author )
{
this.IconPath = iconPath;
this.Name = name;
this.Author = author;
}
public String IconPath
{
get;
set;
}
public String Name
{
get;
set;
}
public String Author
{
get;
set;
}
} CopyVB.NET Public Class ApplicationInfo
Public Sub New(iconPath As String, name As String, author As String)
Me.IconPath = iconPath
Me.Name = name
Me.Author = author
End Sub
Public Property IconPath() As [String]
Get
Return m_IconPath
End Get
Set
m_IconPath = Value
End Set
End Property
Private m_IconPath As [String]
Public Property Name() As [String]
Get
Return m_Name
End Get
Set
m_Name = Value
End Set
End Property
Private m_Name As [String]
Public Property Author() As [String]
Get
Return m_Author
End Get
Set
m_Author = Value
End Set
End Property
Private m_Author As [String]
End Class - Declare two ListBox controls in XAML.
CopyXAML <Grid x:Name="LayoutRoot"
Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<ListBox x:Name="allApplicationsBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="150">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image Grid.Row="0"
HorizontalAlignment="Center"
Source="{Binding IconPath}"
Width="32"
Height="32"
Margin="0 0 5 0" />
<TextBlock Grid.Row="1"
Text="{Binding Name}"
FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding Author}"
Grid.Row="2"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="myApplicationsBox"
Grid.Column="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Image Source="{Binding IconPath}"
Margin="0 0 3 0"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding Name}"
HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<telerik:RadUniformGrid Columns="3"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid> - Switch to the code-behind and declare two ObservableCollections of ApplicationInfo objects. Set the ItemSource property of each ListBox control.
CopyC# public partial class GettingStarted : UserControl
{
public static ObservableCollection<ApplicationInfo> GenerateApplicationInfos()
{
ObservableCollection<ApplicationInfo> data = new ObservableCollection<ApplicationInfo>();
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/Atom.png", "C.E.R.N.", "Large Collider" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/Brush.png", "Imagine Inc.", "Paintbrush" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/CalendarEvents.png", "Control AG", "Lively Calendar" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/CDBurn.png", "The CD Factory", "Fire Burning ROM" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/favorites.png", "Star Factory", "Fav Explorer" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/Connected.png", "Open Org", "IE Fox" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/ChartDot.png", "AA-AZ inc", "Charting" ) );
data.Add( new ApplicationInfo( "/MyProject;component/Images/DragAndDrop/LargeIcons/Games.png", "EB Games", "SuperPlay" ) );
return data;
}
private ObservableCollection<ApplicationInfo> allApplications = GenerateApplicationInfos();
private ObservableCollection<ApplicationInfo> myApplications = new ObservableCollection<ApplicationInfo>();
public GettingStarted()
{
InitializeComponent();
allApplicationsBox.ItemsSource = allApplications;
myApplicationsBox.ItemsSource = myApplications;
}
} CopyVB.NET Public Partial Class GettingStarted
Inherits UserControl
Public Shared Function GenerateApplicationInfos() As ObservableCollection(Of ApplicationInfo)
Dim data As New ObservableCollection(Of ApplicationInfo)()
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/Atom.png", "C.E.R.N.", "Large Collider"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/Brush.png", "Imagine Inc.", "Paintbrush"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/CalendarEvents.png", "Control AG", "Lively Calendar"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/CDBurn.png", "The CD Factory", "Fire Burning ROM"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/favorites.png", "Star Factory", "Fav Explorer"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/Connected.png", "Open Org", "IE Fox"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/ChartDot.png", "AA-AZ inc", "Charting"))
data.Add(New ApplicationInfo("/MyProject;component/Images/DragAndDrop/LargeIcons/Games.png", "EB Games", "SuperPlay"))
Return data
End Function
Private allApplications As ObservableCollection(Of ApplicationInfo) = GenerateApplicationInfos()
Private myApplications As New ObservableCollection(Of ApplicationInfo)()
Public Sub New()
InitializeComponent()
allApplicationsBox.ItemsSource = allApplications
myApplicationsBox.ItemsSource = myApplications
End Sub
End Class - The next step is to allow the drag and drop operation. For example, when you want to implement drag and drop between a ListBox and other controls, you should make the ListBox droppable and its children draggable. However, there are certain scenarios when this is not such a trivial task. If your ListBox is data bound to a collection of business objects (like in this example), you can't make its children draggable because they are not accessible. The solution here is to use Styles, like in the code-snippet below:
CopyXAML <UserControl.Resources>
<DataTemplate x:Key="ApplicationDragTemplate">
<Image Source="{Binding IconPath}"
Stretch="None"
VerticalAlignment="Top" />
</DataTemplate>
<Style TargetType="ListBoxItem"
x:Key="draggableItemStyle">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="telerik:RadDragAndDropManager.AllowDrag"
Value="True" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<ListBox x:Name="allApplicationsBox"
telerik:RadDragAndDropManager.AllowDrop="True"
ItemContainerStyle="{StaticResource draggableItemStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="150">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image Grid.Row="0"
HorizontalAlignment="Center"
Source="{Binding IconPath}"
Width="32"
Height="32"
Margin="0 0 5 0" />
<TextBlock Grid.Row="1"
Text="{Binding Name}"
FontWeight="Bold"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding Author}"
Grid.Row="2"
HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="myApplicationsBox"
telerik:RadDragAndDropManager.AllowDrop="True"
ItemContainerStyle="{StaticResource draggableItemStyle}"
Grid.Column="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Image Source="{Binding IconPath}"
Margin="0 0 3 0"
HorizontalAlignment="Center" />
<TextBlock Text="{Binding Name}"
HorizontalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<telerik:RadUniformGrid Columns="3"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid> - Switch to the code-behind, subscribe to the four DragDrop events:
CopyC# public GettingStarted()
{
InitializeComponent();
allApplicationsBox.ItemsSource = allApplications;
myApplicationsBox.ItemsSource = myApplications;
RadDragAndDropManager.AddDragQueryHandler( this, OnDragQuery );
RadDragAndDropManager.AddDragInfoHandler( this, OnDragInfo );
RadDragAndDropManager.AddDropQueryHandler( this, OnDropQuery );
RadDragAndDropManager.AddDropInfoHandler( this, OnDropInfo );
} CopyVB.NET Public Sub New()
InitializeComponent()
allApplicationsBox.ItemsSource = allApplications
myApplicationsBox.ItemsSource = myApplications
RadDragAndDropManager.AddDragQueryHandler(Me, AddressOf OnDragQuery)
RadDragAndDropManager.AddDragInfoHandler(Me, AddressOf OnDragInfo)
RadDragAndDropManager.AddDropQueryHandler(Me, AddressOf OnDropQuery)
RadDragAndDropManager.AddDropInfoHandler(Me, AddressOf OnDropInfo)
End Sub - Create hollow event handlers:
CopyC#
private void OnDragQuery( object sender, DragDropQueryEventArgs e )
{
}
private void OnDropQuery( object sender, DragDropQueryEventArgs e )
{
}
private void OnDropInfo( object sender, DragDropEventArgs e )
{
}
private void OnDragInfo( object sender, DragDropEventArgs e )
{
} CopyVB.NET
Private Sub OnDragQuery(ByVal sender As Object, ByVal e As DragDropQueryEventArgs)
End Sub
Private Sub OnDropQuery(ByVal sender As Object, ByVal e As DragDropQueryEventArgs)
End Sub
Private Sub OnDropInfo(ByVal sender As Object, ByVal e As DragDropEventArgs)
End Sub
Private Sub OnDragInfo(ByVal sender As Object, ByVal e As DragDropEventArgs)
End Sub - OnDragQuery() event handler. The DragQuery event is raised when the user initiates the drag operation. In the OnDragQuery() event handler, you have to perform the following steps:
- First, getting the dragged element. This is done via the DragDropOptions.Source property.
- Second, an ArrowCue and a custom DragCue are created and set to the DragDropOptions.ArrowCue and DragDropOptions.DragCue properties.
- And finally, the most important step - setting the payload object.
CopyC# private void OnDragQuery( object sender, DragDropQueryEventArgs e )
{
ListBoxItem listBoxItem = e.Options.Source as ListBoxItem;
ListBox box = ItemsControl.ItemsControlFromItemContainer( listBoxItem ) as ListBox;
if ( e.Options.Status == DragStatus.DragQuery && box != null )
{
e.Options.Payload = box.SelectedItem;
ContentControl cue = new ContentControl();
cue.ContentTemplate = this.Resources[ "ApplicationDragTemplate" ] as DataTemplate;
cue.Content = box.SelectedItem;
e.Options.DragCue = cue;
e.Options.ArrowCue = RadDragAndDropManager.GenerateArrowCue();
}
e.QueryResult = true;
} CopyVB.NET Private Sub OnDragQuery(sender As Object, e As DragDropQueryEventArgs)
Dim listBoxItem As ListBoxItem = TryCast(e.Options.Source, ListBoxItem)
Dim box As ListBox = TryCast(ItemsControl.ItemsControlFromItemContainer(listBoxItem), ListBox)
If e.Options.Status = DragStatus.DragQuery AndAlso box IsNot Nothing Then
e.Options.Payload = box.SelectedItem
Dim cue As New ContentControl()
cue.ContentTemplate = TryCast(Me.Resources("ApplicationDragTemplate"), DataTemplate)
cue.Content = box.SelectedItem
e.Options.DragCue = cue
e.Options.ArrowCue = RadDragAndDropManager.GenerateArrowCue()
End If
e.QueryResult = True
End Sub - Note, that a custom DataTemplate is used for the DragCue. It is shown on the code snippet below.
CopyXAML <UserControl.Resources>
<DataTemplate x:Key="ApplicationDragTemplate">
<Image Source="{Binding IconPath}"
Stretch="None"
VerticalAlignment="Top" />
</DataTemplate>
</UserControl.Resources>
- OnDragInfo() event handler. When the drag operation is completed and you are dropping on the appropriate ListBox, then you remove the dragged item from the source ListBox. Note the FindItemsControlParent() method. It is a helper extension method, finding the parent control of the dragged item. In this case, the result returned by the method is the parent ListBox.
CopyC# private void OnDragInfo( object sender, DragDropEventArgs e )
{
ListBoxItem listBoxItem = e.Options.Source as ListBoxItem;
ListBox box = ItemsControl.ItemsControlFromItemContainer( listBoxItem ) as ListBox;
IList<ApplicationInfo> itemsSource = box.ItemsSource as IList<ApplicationInfo>;
ApplicationInfo payload = e.Options.Payload as ApplicationInfo;
if ( e.Options.Status == DragStatus.DragComplete )
{
if ( payload != null && itemsSource.Contains( payload ) )
{
itemsSource.Remove( payload );
}
}
} CopyVB.NET Private Sub OnDragInfo(sender As Object, e As DragDropEventArgs)
Dim listBoxItem As ListBoxItem = TryCast(e.Options.Source, ListBoxItem)
Dim box As ListBox = TryCast(ItemsControl.ItemsControlFromItemContainer(listBoxItem), ListBox)
Dim itemsSource As IList(Of ApplicationInfo) = TryCast(box.ItemsSource, IList(Of ApplicationInfo))
Dim payload As ApplicationInfo = TryCast(e.Options.Payload, ApplicationInfo)
If e.Options.Status = DragStatus.DragComplete Then
If payload IsNot Nothing AndAlso itemsSource.Contains(payload) Then
itemsSource.Remove(payload)
End If
End If
End Sub - OnDropQuery() event handler. The code here is pretty simple. Generally, the only thing you should do here is to allow the drop operation.
CopyC# private void OnDropQuery( object sender, DragDropQueryEventArgs e )
{
ItemsControl box = e.Options.Destination as ItemsControl;
IList<ApplicationInfo> itemsSource = box.ItemsSource as IList<ApplicationInfo>;
ApplicationInfo payload = e.Options.Payload as ApplicationInfo;
e.QueryResult = payload != null && !itemsSource.Contains( payload );
} CopyVB.NET Private Sub OnDropQuery(sender As Object, e As DragDropQueryEventArgs)
Dim box As ItemsControl = TryCast(e.Options.Destination, ItemsControl)
Dim itemsSource As IList(Of ApplicationInfo) = TryCast(box.ItemsSource, IList(Of ApplicationInfo))
Dim payload As ApplicationInfo = TryCast(e.Options.Payload, ApplicationInfo)
e.QueryResult = payload IsNot Nothing AndAlso Not itemsSource.Contains(payload)
End Sub - OnDropInfo() event handler. The final step is to add the dragged item to the destination ListBox.
CopyC# private void OnDropInfo( object sender, DragDropEventArgs e )
{
ItemsControl box = e.Options.Destination as ItemsControl;
IList<ApplicationInfo> itemsSource = box.ItemsSource as IList<ApplicationInfo>;
ApplicationInfo payload = e.Options.Payload as ApplicationInfo;
if ( e.Options.Status == DragStatus.DropComplete )
if ( !itemsSource.Contains( payload ) )
itemsSource.Add( payload );
} CopyVB.NET Private Sub OnDropInfo(sender As Object, e As DragDropEventArgs)
Dim box As ItemsControl = TryCast(e.Options.Destination, ItemsControl)
Dim itemsSource As IList(Of ApplicationInfo) = TryCast(box.ItemsSource, IList(Of ApplicationInfo))
Dim payload As ApplicationInfo = TryCast(e.Options.Payload, ApplicationInfo)
If e.Options.Status = DragStatus.DropComplete Then
If Not itemsSource.Contains(payload) Then
itemsSource.Add(payload)
End If
End If
End Sub - Run your demo. The end result is shown on the snapshot below.
Tip |
|---|
| You could check a live demo demonstrating drag and drop between ListBox controls here. |
See Also
|