在WPF中通过DataTemple实现Drag&Drop控件
2011-04-13 19:33
387 查看
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 }
但是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 }
相关文章推荐
- delphi 控件 TEmbeddedWB 实现超级拖拽 (super Drag&amp;Drop OR inline Drag&amp;Drop)
- WPF 实现拖放的简单实例(Drag & Drop)
- WinForm DataGridView & WPF DataGrid 的拖拽(Drag & Drop)
- Android开发之Drag&Drop框架实现拖放手势
- 人人网首页拖拽上传详解(HTML5 Drag&Drop、FileReader API、FormData)
- Tree控件的Drag&Drop
- 第六部分:实现Drop目标对象(OLE drag&drop 之旅)
- Draggabilly – 轻松实现拖放功能(Drag & Drop)
- javascript中实现拖拽drag & drop效果的几种方法
- 用Vc实现drag&drop打开文件
- WPF实现Drag/Drop操作
- 第三部分:实现IDataObject(OLE drag&drop之旅)
- ASP.NET Atlas实现网站模块(版块)拖放(Drag &amp; Drop)效果
- Internet Explorer 编程简述(十一)实现完美的Inplace Drag & Drop——“超级拖放”
- 关于文件流的模拟上传——人人网首页拖拽上传详解(HTML5 Drag&Drop、FileReader API、formdata) | 彬Go
- ASP.NET Atlas实现网站模块(版块)拖放(Drag & Drop)效果
- 《JavaScript 实战》:实现拖放(Drag & Drop)效果
- 【功能】C# 控件实现内容拖动(DragDrop)功能(SamWang)
- Android开发之Drag&Drop框架实现拖放手势
- 使用ASP.NET Atlas实现拖放(Drag & Drop)效果