Return of .NET  
宠辱不惊,静观堂前花开花落;去留无意,漫随天外云卷云舒。

WPF中提供一套十分简便的实现Drag&Drop的机制,方便了开发人员定制自己的Drag&Drop行为。

但是WPF中提供的Drag&Drop是基于数据传递的,通过Drag把你希望传递的数据放入DataObject对象里, 调用DragDrop.DoDragDrop(), 在Drop事件Hander里就可以获取到你刚才传入的数据,在使对这些数据做处理就完成了整个Drag&Drop行为。

 

实际中经常用到拖拽控件本身,这在WPF中怎么实现呢?笔者想到可以利用WPF中的DataTemple, DataTemple定义了用来展现数据的界面模板,你可以想象即使在界面层,你操作控制的也是一堆数据,这些数据的展现交给DataTemplate来做。那还等什么,利用它来实现Drag&Drop控件吧。

下面是我的一个Sample, 供大家参考:

 

1.首先定义PresenterDataForButton和PresenterDataForTextBox 分别代表 Button 和TextBox控件的Data类型:

 1    public interface ITragable
 2     { 
 3     }
 4     public class PresenterDataForButton :ITragable
 5     {
 6         public string Content
 7         {
 8             get;
 9             set;
10         }
11 
12         public RoutedEventHandler ButtonClickHandler;
13 
14     }
15 
16     public class PresenterDataForTextBox : ITragable
17     {
18         public string Text
19         {
20             get;
21             set;
22         }
23     }

 

2. 利用DataTemple使数据分别展现成Button和TextBox控件,注意本例中DataTemple的定义是放在Window的Resouce中,并且是使用的是DataType,这样整个window中的PresenterDataForButton和PresenterDataForTextBox 都会被展现成相应的控件:

 1 <Window x:Class="MyDragAndDrop.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:local="clr-namespace:MyDragAndDrop"
 5         Title="MainWindow" Height="350" Width="525">
 6     <Window.Resources>
 7         
 8         <DataTemplate DataType="{x:Type local:PresenterDataForButton}">
 9             <Button Content="{Binding Path=Content}"/>
10         </DataTemplate>
11         <DataTemplate DataType="{x:Type local:PresenterDataForTextBox}">
12             <TextBox Text="{Binding Path=Text}"/>
13         </DataTemplate>
14         
15     </Window.Resources>
16         <DockPanel >
17         <ListView  x:Name="listView" DockPanel.Dock="Left"
18                    PreviewMouseLeftButtonDown="listView_PreviewMouseLeftButtonDown" 
19                    PreviewMouseMove="listView_PreviewMouseMove"/>
20         <Canvas Drop="ContentControl_Drop" DockPanel.Dock="Right" 
21                         AllowDrop="True" Background="LightBlue"
22                         DragEnter="ContentControl_DragEnter" Height="260" Width="272">
23             <StackPanel x:Name="myStackPanel"/>
24 
25             </Canvas>
26     </DockPanel>
27 
28 </Window>

3. 最后通过Drag&Drop你的数据,达到拖拽控件的效果。

 

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Windows;
  6 using System.Windows.Controls;
  7 using System.Windows.Data;
  8 using System.Windows.Documents;
  9 using System.Windows.Input;
 10 using System.Windows.Media;
 11 using System.Windows.Media.Imaging;
 12 using System.Windows.Navigation;
 13 using System.Windows.Shapes;
 14 
 15 namespace MyDragAndDrop
 16 {
 17     /// <summary>
 18     /// Interaction logic for MainWindow.xaml
 19     /// </summary>
 20     public partial class MainWindow : Window
 21     {
 22         private Point m_startPoint;
 23         
 24         public MainWindow()
 25         {
 26             InitializeComponent();
 27             this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
 28         }
 29 
 30 
 31         private void MainWindow_Loaded(object sender, RoutedEventArgs e)
 32         {
 33 
 34             this.listView.Items.Add(new PresenterDataForButton
 35             {
 36                 Content = "Click Me",
 37                 ButtonClickHandler = (object sender1, RoutedEventArgs e1) =>
 38                 {
 39                     MessageBox.Show("Clicked");
 40                 }
 41             });
 42 
 43             this.listView.Items.Add(new PresenterDataForTextBox { Text = "It is a TextBox." });
 44 
 45         }
 46 
 47         private void listView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 48         {
 49               m_startPoint = e.GetPosition(null);
 50 
 51         }
 52 
 53         private void listView_PreviewMouseMove(object sender, MouseEventArgs e)
 54         {
 55             // Get the current mouse position
 56             Point mousePos = e.GetPosition(null);
 57             Vector diff = m_startPoint - mousePos;
 58 
 59             if (e.LeftButton == MouseButtonState.Pressed &&
 60                 Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
 61                 Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)
 62             {
 63                 // Get the dragged ListViewItem
 64                 ListView listView = sender as ListView;
 65                 if (null != listView)
 66                 {
 67 
 68                     ListViewItem listViewItem =
 69                         FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
 70 
 71                     if (null != listViewItem)
 72                     {
 73 
 74                         // Find the data behind the ListViewItem
 75                         object dragedObject = listView.ItemContainerGenerator.
 76                            ItemFromContainer(listViewItem);
 77 
 78                         // Initialize the drag & drop operation
 79                         DataObject dragData = new DataObject("myFormat", dragedObject);
 80                         DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Move);
 81                     }
 82                 }
 83             } 
 84 
 85         }
 86 
 87 
 88         // Helper to search up the VisualTree
 89         private static T FindAnchestor<T>(DependencyObject current)
 90             where T : DependencyObject
 91         {
 92             do
 93             {
 94                 if (current is T)
 95                 {
 96                     return (T)current;
 97                 }
 98                 current = VisualTreeHelper.GetParent(current);
 99             }
100             while (current != null);
101             return null;
102         }
103 
104         private void ContentControl_Drop(object sender, DragEventArgs e)
105         {
106             if (e.Data.GetDataPresent("myFormat"))
107             {
108                 ITragable dragedObject = e.Data.GetData("myFormat"as ITragable;
109                 if(null!=dragedObject)
110                 {
111                     Canvas canvas = sender as Canvas;
112                     var content = new ContentControl();
113                     content.Content = dragedObject;
114                     myStackPanel.Children.Add(content);                                       
115                 }
116             }
117 
118         }
119 
120         private void ContentControl_DragEnter(object sender, DragEventArgs e)
121         {
122             if (!e.Data.GetDataPresent(typeof(ITragable)) ||
123                 sender == e.Source)
124             {
125                 e.Effects = DragDropEffects.None;
126             }
127 
128 
129         }
130 
131 
132 
133     }
134 }

 

 

 

posted on 2011-04-13 19:33  消化酶  阅读(1513)  评论(0编辑  收藏  举报