前天整理一份Silverlight 4中拖拽效果实现-附源码下载 在评论中一位园友提到实现不同控件间拖拽效果设想. 其实在项目中原本我遇到最初拖拽实现就是一个从TreeView中拖拽到一个ListBox中.中午正好看了Silverlight.net BBS和CrraySun.com上讨论.做了一个简单Demo实现.先看看效果:
左边Listbox,右边Treeview.实现步骤如下
A:页面布局:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 < Grid.RowDefinitions >
3 < RowDefinition Height ="40" ></ RowDefinition >
4 < RowDefinition Height ="350" ></ RowDefinition >
5 < RowDefinition Height ="10*" />
6 </ Grid.RowDefinitions >
7 < Grid.ColumnDefinitions >
8 < ColumnDefinition Width ="300" ></ ColumnDefinition >
9 < ColumnDefinition Width ="300" ></ ColumnDefinition >
10 < ColumnDefinition Width ="200*" />
11 </ Grid.ColumnDefinitions >
12
13 < TextBlock Text ="Drag Listbox to Treeview" Foreground ="Red" FontFamily ="Comic Sans MS" FontSize ="16" Grid.ColumnSpan ="2" Margin ="85,12,162,0" ></ TextBlock >
14 <!-- 左边一个listBox -->
15 < toolKit:ListBoxDragDropTarget AllowDrop ="True" Grid.Row ="1" Grid.Column ="0" >
16 < ListBox x:Name ="customerListBoxMain" Height ="240" Width ="215" SelectionMode ="Extended" DisplayMemberPath ="CustomerName" BorderBrush ="Black" BorderThickness ="1" >
17 < ListBox.ItemsPanel >
18 < ItemsPanelTemplate >
19 < StackPanel Orientation ="Vertical" />
20 </ ItemsPanelTemplate >
21 </ ListBox.ItemsPanel >
22 </ ListBox >
23
24 </ toolKit:ListBoxDragDropTarget >
25
26 <!-- 右边一个Treeview -->
27 < toolKit:TreeViewDragDropTarget AllowDrop ="True" Grid.Row ="1" Grid.Column ="1" BorderThickness ="1" BorderBrush ="Red" >
28 <!-- 定义一个数据模板 -->
29 < toolKit:TreeViewDragDropTarget.Resources >
30 < my:HierarchicalDataTemplate x:Name ="datetmp" ItemsSource =" {Binding Customer} " >
31 < TextBlock Text =" {Binding CustomerName} " />
32 </ my:HierarchicalDataTemplate >
33 </ toolKit:TreeViewDragDropTarget.Resources >
34 < sdk:TreeView x:Name ="AcceptTreeview" Height ="240" Width ="215" ItemTemplate =" {StaticResource datetmp} " > </ sdk:TreeView >
35
36 </ toolKit:TreeViewDragDropTarget >
37 </ Grid >
同上篇不同在TreeView中使用到了HierarchicalDataTemplate数据模板来定义Treeview数据显示. HierarchicalDataTemplate 数据模板默认是不添加的, 所以需要在页面添加引用如下:
至于HierarchicalDataTemplate如何使用请参见MSDN.
B:数据绑定-后台代码
同样为了演示方便 直接写了一个类用来ListBox和Treeview中提供所需数据.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 /// 为了达到演示目的 当前类提供list数据
3 /// Author:chenkai Date:2010年5月28日10:21:36
4 /// </summary>
5 public class ProvideDate
6 {
7 public static List < Customer > GetAllCustomerList()
8 {
9 List < Customer > getcuslist = new List < Customer > ();
10 getcuslist.Add( new Customer { CustomerName = " JackChen " });
11 getcuslist.Add( new Customer { CustomerName = " Arrmy " });
12 getcuslist.Add( new Customer { CustomerName = " SunSkyUnion " });
13 getcuslist.Add( new Customer { CustomerName = " 西藏拉萨 " });
14 getcuslist.Add( new Customer { CustomerName = " 甘肃玉门关 " });
15
16 return getcuslist;
17 }
18
19
20 public static List < Customer > GetAllCustomerTreeList()
21 {
22 List < Customer > getcuslist = new List < Customer > ();
23 getcuslist.Add( new Customer { CustomerName = " markChen " });
24 getcuslist.Add( new Customer { CustomerName = " KaiDun " });
25 getcuslist.Add( new Customer { CustomerName = " GuideInformation " });
26 getcuslist.Add( new Customer { CustomerName = " 三门峡函谷关 " });
27 getcuslist.Add( new Customer { CustomerName = " 嘉峪关 " });
28 getcuslist.Add( new Customer { CustomerName = " 泰山 " });
29 getcuslist.Add( new Customer { CustomerName = " 嵩山 " });
30
31 return getcuslist;
32 }
33 }
34
35 public class Customer
36 {
37 public string CustomerName { get ; set ; }
38 }
页面数据绑定:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
2 List < Customer > getcuslist = TestSilverlightOutOfBrowerDemo.Date.ProvideDate.GetAllCustomerList();
3 if (getcuslist != null )
4 {
5 ObservableCollection < Customer > getlist = new ObservableCollection < Customer > ();
6 foreach (Customer getcus in getcuslist)
7 {
8 getlist.Add(getcus);
9 }
10 this .customerListBoxMain.ItemsSource = getlist;
11 }
12
13 // 绑定Treeview数据
14 List < Customer > gettreeviewlist = TestSilverlightOutOfBrowerDemo.Date.ProvideDate.GetAllCustomerTreeList();
15 ObservableCollection < Customer > getviewlist = new ObservableCollection < Customer > ();
16 foreach (Customer getcustree in gettreeviewlist)
17 {
18 getviewlist.Add(getcustree);
19 }
20
21 this .AcceptTreeview.ItemsSource = getviewlist;
22
ObservableCollection动态数据集合,这次数据通过绑定来实现.动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知 具体参见:MSDN
如上即简单实现了一个listbox向一个TreeView中拖拽实现,其实我当初在实现这问题,参考大量资料. 我想说一下个人对这个拖拽实现思路理解.首先我想说的是在整个拖拽过程事件执行过程,
注意:虽然实现了Treeview在Listbox之间拖拽,但真正拖拽事件发生是在TreeViewDragDropTarget和ListBoxDragDropTarget控件中. 不要误认为是ListBox或Treeview本身.
(1)先看看TreeViewDragDropTarget关于Drag事件.
分别为Drop,DragOver, DragLeave,DragEnter. 这三个真正执行顺序如下:
执行场景:当把一个Listbox一个项拖拽到Treeview时 从DragEnter开始执行到DragOver. 其实上面实现完全是利用数据模板和DragDropTraget控件便利. 来整理一下在Sl3.0中实现一个拖拽需要具体步骤拆分:
A:实现一个拖动图像,作为开始拖拽时的快照
B:找到程序的root visual根视觉(如StackPanel)
C:将拖动图像添加到根视觉,并得到它的绝对坐标[动态坐标数据-难点]
D:在运动时保持鼠标与拖动图像同步,随时给出是否在落下目标(drop target)上的视觉反馈 [需要动画效果]
E:处理用户释放鼠标时刻,当经过落下目标时可以适当地动作,甚至可以显示一段不错的动画
如此就在Silverlight 3.0拖拽效果.当然在4.0加以封装来实现.如何来获得拖拽实时数据 和SL3.0有点不同.
(2)获得拖拽实时数据
其实拖拽时listBox中数据都放在ItemContainer数据容器中,当拖拽一项时既是反映到ItemContainer中就是Remove删除一项,反而言之 接受一方Treeview中数据容器这是Add添加一个新项. 这就给我们提供一个监听拖拽数据机会.我们可以在listbox中ItemContainerGenerator.ItemsChanged定义一个监听事件. 来获取当前拖拽项.
2 this .AcceptTreeview.ItemContainerGenerator.ItemsChanged += new System.Windows.Controls.Primitives.ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);
事件实现:
2 {
3 if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
4 {
5 // e.Position获取集合中更改发生的位置
7 int index = (e.Position.Index + e.Position.Offset);
8 MessageBox.Show( " total: " + this .AcceptTreeview.Items.Count.ToString() + " Index: " + index.ToString());
9 object obj = this .AcceptTreeview.Items[index];
10
11 if (obj != null )
12 {
13 TreeViewItem getitem = obj as TreeViewItem;
14 MessageBox.Show(getitem.Header.ToString());
15
16 ListBoxItem getboxitem = obj as ListBoxItem;
17 MessageBox.Show(getboxitem.Content.ToString());
18 }
19 }
20 }
通过附属的ItemsChangedEventArgs 附带事件信息. 来判断当前对数据容器ItemContainer操作类型,System.Collections.Specialized.NotifyCollectionChangedAction是一个操作枚举. 包含None Add REmove. 判断拖拽状态后即可通过E.Position来获取数据项发生的位置. 集合通过装换获得具体拖拽项.当然也可定义其他操作.