Hi,
I'm just looking for a simple example of how to drap and drop an item from one listbox to another. I'm using datatemplates for both listboxes and i'd like to see the item in the preview when dragging.
** something that's compatible with the feb ctp 06 and in c# would be great too.
Thanks in advance.

drag and drop between list boxes
clarkiwrc
the zipped files for the drag drop operations in C# are located here:
http://blogs.msdn.com/llobo/archive/2006/04/11/573560.aspx
daat99
thomasn
freeflyr, I have a series of posts about drag-drop over at http://blogs.msdn.com/marcelolr/.
The first post is http://blogs.msdn.com/marcelolr/archive/2006/03/02/542641.aspx, and the preview adorner gets introduced in http://blogs.msdn.com/marcelolr/archive/2006/03/03/543301.aspx.
I'll post the complete code in a couple of posts - there are still a couple of things I'd like to touch upon to build the sample out a bit more.
GMichaels
In case anyone wants to just build the final result of the Drag & Drop series to date, here is the complete result of Marcelo's walkthroughs on drag and drop in VB.NET & C#.
XAML - Window1.xaml
______________________________
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SampleDragDrop" Height="300" Width="300"
>
<Window.Resources>
<XmlDataProvider x:Key="MyData">
<x:XData>
<Sections xmlns="" Title="Library Favorites">
<Section Name=".NET Development">
<Article Name="Articles and Overview" />
<Article Name=".NET Performance" />
<Article Name="Windows Vista" />
<Article Name="XML and the .NET Framework" />
</Section>
</Sections>
</x:XData>
</XmlDataProvider>
<DataTemplate x:Key="ArticleTemplate">
<TextBlock FontSize="10pt" Text="{Binding XPath=@Name}" />
</DataTemplate>
</Window.Resources>
<DockPanel>
<Border DockPanel.Dock="Top" BorderBrush="DarkGray" BorderThickness="2" Padding="4">
<TextBlock FontSize="8pt" FontFamily="Tahoma" TextWrapping="Wrap">
<Bold>
Drag Sample
</Bold>
<LineBreak />
<Run>
This sample demonstrates using a DataObject for dragging "pure" data.
</Run>
</TextBlock>
</Border>
<ListBox Name="myListBox" AllowDrop="True"
ItemsSource="{Binding Source={StaticResource MyData}, XPath=/Sections/Section/Article}"
ItemTemplate="{StaticResource ArticleTemplate}">
<ListBox.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="DarkBlue" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</ListBox.Background>
</ListBox>
</DockPanel>
</Window>
Code-Behind in C# - Window1.xaml.cs
____________________________________________
public partial class Window1 : Window
{
private Point m_StartPoint;
private bool m_IsDown;
private System.Xml.XmlElement m_OriginalElement;
private DropPreviewAdorner m_OverlayElement;
private System.Xml.XmlElement m_RemoteElement;
private static DataFormat m_MyFormat = DataFormats.GetDataFormat( "My Love-ly Format" );
public Window1()
{
InitializeComponent();
}
protected override void OnInitialized( EventArgs e )
{
base.OnInitialized( e );
myListBox.PreviewMouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler( MyCanvas_PreviewMouseLeftButtonDown );
myListBox.PreviewMouseMove += new System.Windows.Input.MouseEventHandler( MyCanvas_PreviewMouseMove );
myListBox.PreviewDragOver += new DragEventHandler( MyCanvas_PreviewDragOver );
myListBox.PreviewDrop += new DragEventHandler( MyCanvas_PreviewDrop );
myListBox.PreviewDragEnter += new DragEventHandler( MyCanvas_PreviewDragEnter );
myListBox.PreviewDragLeave += new DragEventHandler( MyCanvas_PreviewDragLeave );
}
private void MyCanvas_PreviewMouseLeftButtonDown( object sender, System.Windows.Input.MouseButtonEventArgs e )
{
m_OriginalElement = GetElementFromPoint( myListBox, e.GetPosition( myListBox ) );
if ( m_OriginalElement == null )
{
return;
}
m_IsDown = true;
m_StartPoint = e.GetPosition( myListBox );
}
private System.Xml.XmlElement GetElementFromPoint( ListBox box, Point point )
{
UIElement element = (UIElement)box.InputHitTest( point );
while ( true )
{
if ( element == box )
{
return null;
}
object item = box.ItemContainerGenerator.ItemFromContainer( element );
bool itemFound = !( item.Equals( DependencyProperty.UnsetValue ) );
if ( itemFound )
{
return item as System.Xml.XmlElement;
}
element = (UIElement)VisualTreeHelper.GetParent( element );
}
}
private void MyCanvas_PreviewMouseMove( object sender, System.Windows.Input.MouseEventArgs e )
{
if ( m_IsDown )
{
if ( Math.Abs( e.GetPosition( myListBox ).X - m_StartPoint.X ) > SystemParameters.MinimumHorizontalDragDistance && Math.Abs( e.GetPosition( myListBox ).Y - m_StartPoint.Y ) > SystemParameters.MinimumVerticalDragDistance )
{
DragStarted();
}
}
}
private void DragStarted()
{
m_IsDown = false;
string serializedObject = m_OriginalElement.OuterXml;
DataObject data = new DataObject();
data.SetData( m_MyFormat.Name, serializedObject );
DragDropEffects effects = DragDrop.DoDragDrop( myListBox, data, DragDropEffects.Copy | DragDropEffects.Move );
if ( effects == DragDropEffects.Move )
{
// Remove the element.
m_OriginalElement.ParentNode.RemoveChild( m_OriginalElement );
m_OriginalElement = null;
}
}
private void DragMoved()
{
Point currentPosition = System.Windows.Input.Mouse.GetPosition( myListBox );
m_OverlayElement.LeftOffset = currentPosition.X - m_StartPoint.X;
m_OverlayElement.TopOffset = currentPosition.Y - m_StartPoint.Y;
}
private void MyCanvas_PreviewDragOver( object sender, System.Windows.DragEventArgs e )
{
if ( !( UpdateEffects( e ) ) )
{
return;
}
Point currentPosition = (Point) e.GetPosition( (IInputElement) this.Content );
m_OverlayElement.LeftOffset = currentPosition.X;
m_OverlayElement.TopOffset = currentPosition.Y;
e.Handled = true;
}
private void MyCanvas_PreviewDrop( object sender, System.Windows.DragEventArgs e )
{
if ( !( UpdateEffects( e ) ) )
{
return;
}
XmlDataProvider dataProvider = (XmlDataProvider) FindResource( "MyData" );
System.Xml.XmlDocument document = dataProvider.Document;
System.Xml.XmlElement node = (System.Xml.XmlElement) dataProvider.Document.ImportNode( m_RemoteElement, true );
dataProvider.Document.GetElementsByTagName( "Section" )[0].AppendChild(node);
AdornerLayer.GetAdornerLayer( (System.Windows.Media.Visual) this.Content ).Remove( m_OverlayElement );
m_RemoteElement = null;
m_OverlayElement = null;
e.Handled = true;
}
private void MyCanvas_PreviewDragEnter( object sender, System.Windows.DragEventArgs e )
{
if ( !( UpdateEffects( e ) ) )
{
return;
}
string serializedObject = (string) e.Data.GetData( m_MyFormat.Name );
System.Xml.XmlDocument document = new System.Xml.XmlDocument();
document.LoadXml( serializedObject );
m_RemoteElement = document.DocumentElement;
ContentPresenter presenter = new ContentPresenter();
presenter.Content = m_RemoteElement;
presenter.ContentTemplate = myListBox.ItemTemplate;
AdornerLayer layer;
m_OverlayElement = new DropPreviewAdorner( (UIElement)this.Content, presenter );
layer = AdornerLayer.GetAdornerLayer( (System.Windows.Media.Visual) this.Content );
layer.Add( m_OverlayElement );
e.Handled = true;
}
private void MyCanvas_PreviewDragLeave( object sender, System.Windows.DragEventArgs e )
{
if ( m_OverlayElement == null )
{
return;
}
AdornerLayer.GetAdornerLayer( ( System.Windows.Media.Visual ) this.Content ).Remove( m_OverlayElement );
m_OverlayElement = null;
m_RemoteElement = null;
e.Handled = true;
}
private bool UpdateEffects( System.Windows.DragEventArgs e )
{
if ( !( e.Data.GetDataPresent( m_MyFormat.Name ) ) )
{
e.Effects = DragDropEffects.None;
return false;
}
if ( ( e.AllowedEffects & DragDropEffects.Copy ) == 0 && ( e.AllowedEffects & DragDropEffects.Move ) == 0 )
{
e.Effects = DragDropEffects.None;
return false;
}
if ( ( e.AllowedEffects & DragDropEffects.Copy ) != 0 && ( e.AllowedEffects & DragDropEffects.Move ) != 0 )
{
if ( ( e.KeyStates & DragDropKeyStates.ControlKey ) != 0 )
{
e.Effects = DragDropEffects.Copy;
}
else
{
e.Effects = DragDropEffects.Move;
}
}
else
{
e.Effects = e.AllowedEffects & (( DragDropEffects.Copy | DragDropEffects.Move ) );
}
return true;
}
#region Adorner Class
class DropPreviewAdorner : Adorner
{
public DropPreviewAdorner( UIElement adornedElement, UIElement adorningElement )
: base( adornedElement )
{
VisualBrush brush = new VisualBrush( adorningElement );
m_Child = new Rectangle();
m_Child.Width = adorningElement.RenderSize.Width;
m_Child.Height = adorningElement.RenderSize.Height;
m_Child.Fill = brush;
m_Child.IsHitTestVisible = false;
System.Windows.Media.Animation.DoubleAnimation animation;
animation = new System.Windows.Media.Animation.DoubleAnimation( 0.3, 1, new Duration( TimeSpan.FromSeconds( 1 ) ) );
animation.AutoReverse = true;
animation.RepeatBehavior = System.Windows.Media.Animation.RepeatBehavior.Forever;
brush.BeginAnimation( System.Windows.Media.Brush.OpacityProperty, animation );
}
private Rectangle m_Child;
private double m_LeftOffset;
private double m_TopOffset;
protected override System.Windows.Size MeasureOverride( System.Windows.Size constraint )
{
m_Child.Measure( constraint );
return m_Child.DesiredSize;
}
protected override System.Windows.Size ArrangeOverride( System.Windows.Size finalSize )
{
m_Child.Arrange( new Rect( finalSize ) );
return finalSize;
}
protected override System.Windows.Media.Visual GetVisualChild( int index )
{
return m_Child;
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
public double LeftOffset
{
get
{
return m_LeftOffset;
}
set
{
m_LeftOffset = value;
UpdatePosition();
}
}
public double TopOffset
{
get
{
return m_TopOffset;
}
set
{
m_TopOffset = value;
UpdatePosition();
}
}
private void UpdatePosition()
{
AdornerLayer adornerLayer = this.Parent as AdornerLayer;
if ( adornerLayer != null )
{
adornerLayer.Update( AdornedElement );
}
}
public override System.Windows.Media.GeneralTransform GetDesiredTransform( System.Windows.Media.GeneralTransform transform )
{
GeneralTransformGroup result = new GeneralTransformGroup();
result.Children.Add( base.GetDesiredTransform( transform ) );
result.Children.Add( new TranslateTransform( LeftOffset, TopOffset ) );
return result;
}
}
#endregion
Code-Behind in VB.NET - Window1.xaml.vb
______________________________________________
Partial Public Class Window1
Inherits Window
Class DropPreviewAdorner
Inherits Adorner
Public Sub New(ByVal adornedElement As UIElement, _
ByVal adorningElement As UIElement)
MyBase.New(adornedElement)
Dim brush As VisualBrush = New VisualBrush(adorningElement)
m_Child = New Rectangle()
m_Child.Width = adorningElement.RenderSize.Width
m_Child.Height = adorningElement.RenderSize.Height
m_Child.Fill = brush
m_Child.IsHitTestVisible = False
Dim animation As System.Windows.Media.Animation.DoubleAnimation
animation = New System.Windows.Media.Animation.DoubleAnimation(0.3, 1, New Duration(TimeSpan.FromSeconds(1)))
animation.AutoReverse = True
animation.RepeatBehavior = System.Windows.Media.Animation.RepeatBehavior.Forever
brush.BeginAnimation(System.Windows.Media.Brush.OpacityProperty, animation)
End Sub
' Adding some basic fields to help us keep track of where we are and what we render
Private m_Child As Rectangle
Private m_LeftOffset As Double
Private m_TopOffset As Double
Protected Overrides Function MeasureOverride(ByVal constraint As System.Windows.Size) As System.Windows.Size
m_Child.Measure(constraint)
Return m_Child.DesiredSize
End Function
Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size
m_Child.Arrange(New Rect(finalSize))
Return finalSize
End Function
Protected Overrides Function GetVisualChild(ByVal index As Integer) As System.Windows.Media.Visual
Return m_Child
End Function
Protected Overrides ReadOnly Property VisualChildrenCount() As Integer
Get
Return 1
End Get
End Property
Public Property LeftOffset() As Double
Get
Return m_LeftOffset
End Get
Set(ByVal value As Double)
m_LeftOffset = value
UpdatePosition()
End Set
End Property
Public Property TopOffset() As Double
Get
Return m_TopOffset
End Get
Set(ByVal value As Double)
m_TopOffset = value
UpdatePosition()
End Set
End Property
Private Sub UpdatePosition()
Dim adornerLayer As AdornerLayer = Me.Parent
If Not adornerLayer Is Nothing Then
adornerLayer.Update(AdornedElement)
End If
End Sub
Public Overrides Function GetDesiredTransform(ByVal transform As System.Windows.Media.GeneralTransform) As System.Windows.Media.GeneralTransform
Dim result As GeneralTransformGroup = New GeneralTransformGroup()
result.Children.Add(MyBase.GetDesiredTransform(transform))
result.Children.Add(New TranslateTransform(LeftOffset, TopOffset))
Return result
End Function
End Class
Private m_StartPoint As Point ' Where did the mouse start off from
Private m_IsDown As Boolean ' Is the mouse down right now
Private m_OriginalElement As System.Xml.XmlElement ' What is it that we're dragging
Private m_OverlayElement As DropPreviewAdorner ' What is it that we're using to show
Private m_RemoteElement As System.Xml.XmlElement
Private Shared m_MyFormat As DataFormat = DataFormats.GetDataFormat("My Love-ly Format")
Public Sub New()
InitializeComponent()
End Sub
Private Sub myListBox_PreviewMouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles myListBox.PreviewMouseLeftButtonDown
m_OriginalElement = GetElementFromPoint(myListBox, e.GetPosition(myListBox))
If m_OriginalElement Is Nothing Then Exit Sub
m_IsDown = True
m_StartPoint = e.GetPosition(myListBox)
End Sub
Private Function GetElementFromPoint(ByVal box As ListBox, ByVal point As Point) As System.Xml.XmlElement
Dim element As UIElement = box.InputHitTest(point)
While True
If element Is box Then Return Nothing
Dim item As Object = box.ItemContainerGenerator.ItemFromContainer(element)
Dim itemFound As Boolean = Not item.Equals(DependencyProperty.UnsetValue)
If itemFound Then Return item
element = VisualTreeHelper.GetParent(element)
End While
Return Nothing
End Function
Private Sub myListBox_PreviewMouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles myListBox.PreviewMouseMove
If m_IsDown Then
If Math.Abs(e.GetPosition(myListBox).X - m_StartPoint.X) > SystemParameters.MinimumHorizontalDragDistance AndAlso _
Math.Abs(e.GetPosition(myListBox).Y - m_StartPoint.Y) > SystemParameters.MinimumVerticalDragDistance Then
DragStarted()
End If
End If
End Sub
Private Sub DragStarted()
m_IsDown = False
Dim serializedObject As String = m_OriginalElement.OuterXml
Dim data As DataObject = New DataObject()
data.SetData(m_MyFormat.Name, serializedObject)
Dim effects As DragDropEffects = _
DragDrop.DoDragDrop(myListBox, data, DragDropEffects.Copy Or DragDropEffects.Move)
If effects And DragDropEffects.Move Then
' Remove the element.
m_OriginalElement.ParentNode.RemoveChild(m_OriginalElement)
m_OriginalElement = Nothing
End If
End Sub
Private Sub DragMoved()
Dim currentPosition As Point = System.Windows.Input.Mouse.GetPosition(myListBox)
m_OverlayElement.LeftOffset = currentPosition.X - m_StartPoint.X
m_OverlayElement.TopOffset = currentPosition.Y - m_StartPoint.Y
End Sub
Private Sub myListBox_PreviewDragOver(ByVal sender As Object, ByVal e As System.Windows.DragEventArgs) Handles myListBox.PreviewDragOver
If Not UpdateEffects(e) Then
Exit Sub
End If
Dim currentPosition As Point = e.GetPosition(Me.Content)
m_OverlayElement.LeftOffset = currentPosition.X
m_OverlayElement.TopOffset = currentPosition.Y
e.Handled = True
End Sub
Private Sub myListBox_PreviewDrop(ByVal sender As Object, ByVal e As System.Windows.DragEventArgs) Handles myListBox.PreviewDrop
If Not UpdateEffects(e) Then
Exit Sub
End If
' Add the element.
Dim dataProvider As XmlDataProvider = FindResource("MyData")
Dim document As System.Xml.XmlDocument = dataProvider.Document
Dim node As System.Xml.XmlElement = dataProvider.Document.ImportNode(m_RemoteElement, True)
dataProvider.Document.GetElementsByTagName("Section")(0).AppendChild(node)
' Cleanup
AdornerLayer.GetAdornerLayer(Me.Content).Remove(m_OverlayElement)
m_RemoteElement = Nothing
m_OverlayElement = Nothing
e.Handled = True
End Sub
Private Sub myListBox_PreviewDragEnter(ByVal sender As Object, ByVal e As System.Windows.DragEventArgs) Handles myListBox.PreviewDragEnter
If Not UpdateEffects(e) Then
Exit Sub
End If
' First, we deserialize the object provided to us.
Dim serializedObject As String = e.Data.GetData(m_MyFormat.Name)
Dim document As System.Xml.XmlDocument = New System.Xml.XmlDocument()
document.LoadXml(serializedObject)
m_RemoteElement = document.DocumentElement
' Now, create something we can render with.
Dim presenter As ContentPresenter = New ContentPresenter()
presenter.Content = m_RemoteElement
presenter.ContentTemplate = myListBox.ItemTemplate
' Next, create an adorner for it.
Dim layer As AdornerLayer
m_OverlayElement = New DropPreviewAdorner(Me.Content, presenter)
layer = AdornerLayer.GetAdornerLayer(Me.Content)
layer.Add(m_OverlayElement)
e.Handled = True
End Sub
Private Sub myListBox_PreviewDragLeave(ByVal sender As Object, ByVal e As System.Windows.DragEventArgs) Handles myListBox.PreviewDragLeave
If m_OverlayElement Is Nothing Then Exit Sub
AdornerLayer.GetAdornerLayer(Me.Content).Remove(m_OverlayElement)
m_OverlayElement = Nothing
m_RemoteElement = Nothing
e.Handled = True
End Sub
Private Function UpdateEffects(ByVal e As System.Windows.DragEventArgs) As Boolean
' If we don't know what we're talking about, we shouldn't do anything.
If Not e.Data.GetDataPresent(m_MyFormat.Name) Then
e.Effects = DragDropEffects.None
Return False
End If
' If we can't copy or move, we shouldn't do anything (eg: provider wants us to link).
If (e.AllowedEffects And DragDropEffects.Copy) = 0 AndAlso _
(e.AllowedEffects And DragDropEffects.Move) = 0 Then
e.Effects = DragDropEffects.None
Return False
End If
' Figure out whether we should copy or move. If we can do either, we'll move unless
' Ctrl is pressed.
If (e.AllowedEffects And DragDropEffects.Copy) <> 0 AndAlso _
(e.AllowedEffects And DragDropEffects.Move) <> 0 Then
If (e.KeyStates And DragDropKeyStates.ControlKey) <> 0 Then
e.Effects = DragDropEffects.Copy
Else
e.Effects = DragDropEffects.Move
End If
Else
e.Effects = e.AllowedEffects And Not (DragDropEffects.Copy Or DragDropEffects.Move)
End If
Return True
End Function
End Class
Drak Swordsman
You might want to take a look at Mercelo's blog, there are at least 2 or 3 examples of drag and drop, the latest particularly looks alot like what your looking for.
http://blogs.msdn.com/marcelolr/archive/category/11786.aspx
HowardCarr
Hal T
Thanks for the response but marcelo's example seems to be incomplete, i tried to reconstruct it but he declares a variable of type DropPreviewAdorner which does not exist as far as i can see... as i mentioned i am running the feb ctp so perhaps that's the reason but i'd still like to see some code that works on it if anyone has it.