Silverlight4不同控件间拖拽实现-附源码下载

简介:

前天整理一份Silverlight 4中拖拽效果实现-附源码下载  评论中一位园友提到实现不同控件间拖拽效果设想. 其实在项目中原本我遇到最初拖拽实现就是一个从TreeView中拖拽到一个ListBox中.中午正好看了Silverlight.net BBS和CrraySun.com上讨论.做了一个简单Demo实现.先看看效果:

左边Listbox,右边Treeview.实现步骤如下

A:页面布局:

 
  1. <Grid x:Name="LayoutRoot" Background="White"   HorizontalAlignment="Center" VerticalAlignment="Center">  
  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 数据模板默认是不添加的, 所以需要在页面添加引用如下:

 
  1. xmlns:my="clr-namespace:System.Windows;assembly=System.Windows.Controls" 

至于HierarchicalDataTemplate如何使用请参见MSDN.

B:数据绑定-后台代码

同样为了演示方便 直接写了一个类用来ListBox和Treeview中提供所需数据. 

 
  1. /// <summary>  
  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.      public class Customer  
  35.      {  
  36.          public string CustomerName { get; set; }  
  37.      } 

页面数据绑定: 

 
  1. //绑定ListBox数据  
  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; 

因为使用ObservableCollection一个动态数据集合,需要在添加一个空间引用:

 
  1. using System.Collections.ObjectModel; 

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定义一个监听事件. 来获取当前拖拽项.

 
  1. //附属一个监听事件 ItemsChanged 事件由 IItemContainerGenerator 引发,以通知布局项集合已更改  
  2. this.AcceptTreeview.ItemContainerGenerator.ItemsChanged += new System.Windows.Controls.Primitives.ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);  

事件实现:

 
  1. void ItemContainerGenerator_ItemsChanged(object sender, System.Windows.Controls.Primitives.ItemsChangedEventArgs e)  
  2.          {  
  3.              if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)  
  4.              {  
  5.                  //e.Position获取集合中更改发生的位置  
  6.                  int index = (e.Position.Index + e.Position.Offset);  
  7.                  MessageBox.Show("total:" + this.AcceptTreeview.Items.Count.ToString() + "Index:" + index.ToString());  
  8.                  object obj = this.AcceptTreeview.Items[index];  
  9.    
  10.                  if (obj != null)  
  11.                  {  
  12.                      TreeViewItem getitem = obj as TreeViewItem;  
  13.                      MessageBox.Show(getitem.Header.ToString());  
  14.    
  15.                      ListBoxItem getboxitem = obj as ListBoxItem;  
  16.                      MessageBox.Show(getboxitem.Content.ToString());  
  17.                  }  
  18.              }  
  19.          } 

通过附属的ItemsChangedEventArgs 附带事件信息. 来判断当前对数据容器ItemContainer操作类型,System.Collections.Specialized.NotifyCollectionChangedAction是一个操作枚举. 包含None Add REmove. 判断拖拽状态后即可通过E.Position来获取数据项发生的位置. 集合通过装换获得具体拖拽项.当然也可定义其他操作. 



本文转自chenkaiunion 51CTO博客,原文链接:http://blog.51cto.com/chenkai/764912


相关文章

热门文章

最新文章