在WPF中如何实现列表控件的拖拽操作

如果想要建立控件事件Drag & Drop 的结果, 从一个控件中的某一项拖动到另一个控件中,使用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 >


后台代码 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;
  }


  
Adorner Class


后台代码 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.31New 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 IntegerAs 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 ObjectByVal 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 ObjectByVal 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 ObjectByVal 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 ObjectByVal 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 ObjectByVal 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 ObjectByVal 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

你可能感兴趣的:(WPF)