天天看点

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

<a target="_blank" href="http://blog.51cto.com/attachment/201201/181904442.jpg"></a>

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

A:页面布局:

&lt;Grid x:Name="LayoutRoot" Background="White"   HorizontalAlignment="Center" VerticalAlignment="Center"&gt;  

         &lt;Grid.RowDefinitions&gt;  

             &lt;RowDefinition Height="40"&gt;&lt;/RowDefinition&gt;  

             &lt;RowDefinition Height="350"&gt;&lt;/RowDefinition&gt;  

             &lt;RowDefinition Height="10*" /&gt;  

         &lt;/Grid.RowDefinitions&gt;  

         &lt;Grid.ColumnDefinitions&gt;  

             &lt;ColumnDefinition Width="300"&gt;&lt;/ColumnDefinition&gt;  

             &lt;ColumnDefinition Width="200*" /&gt;  

         &lt;/Grid.ColumnDefinitions&gt;  

         &lt;TextBlock Text="Drag  Listbox to Treeview" Foreground="Red" FontFamily="Comic Sans MS" FontSize="16" Grid.ColumnSpan="2" Margin="85,12,162,0"&gt;&lt;/TextBlock&gt;  

         &lt;!--左边一个listBox--&gt;  

         &lt;toolKit:ListBoxDragDropTarget AllowDrop="True" Grid.Row="1" Grid.Column="0" &gt;  

             &lt;ListBox x:Name="customerListBoxMain" Height="240" Width="215" SelectionMode="Extended"   DisplayMemberPath="CustomerName" BorderBrush="Black" BorderThickness="1"&gt;  

                 &lt;ListBox.ItemsPanel&gt;  

                     &lt;ItemsPanelTemplate&gt;  

                         &lt;StackPanel Orientation="Vertical"/&gt;  

                     &lt;/ItemsPanelTemplate&gt;  

                 &lt;/ListBox.ItemsPanel&gt;  

             &lt;/ListBox&gt;  

         &lt;/toolKit:ListBoxDragDropTarget&gt;  

         &lt;!--右边一个Treeview--&gt;  

         &lt;toolKit:TreeViewDragDropTarget AllowDrop="True" Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="Red"&gt;  

             &lt;!--定义一个数据模板--&gt;  

             &lt;toolKit:TreeViewDragDropTarget.Resources&gt;  

                 &lt;my:HierarchicalDataTemplate x:Name="datetmp" ItemsSource="{Binding Customer}"&gt;  

                     &lt;TextBlock Text="{Binding CustomerName}"/&gt;  

                 &lt;/my:HierarchicalDataTemplate&gt;  

             &lt;/toolKit:TreeViewDragDropTarget.Resources&gt;  

             &lt;sdk:TreeView x:Name="AcceptTreeview" Height="240" Width="215" ItemTemplate="{StaticResource datetmp}"&gt; &lt;/sdk:TreeView&gt;  

         &lt;/toolKit:TreeViewDragDropTarget&gt;  

     &lt;/Grid&gt; 

同上篇不同在TreeView中使用到了HierarchicalDataTemplate数据模板来定义Treeview数据显示. HierarchicalDataTemplate 数据模板默认是不添加的, 所以需要在页面添加引用如下:

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

B:数据绑定-后台代码

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

/// &lt;summary&gt;  

     /// 为了达到演示目的 当前类提供list数据  

     /// Author:chenkai Date:2010年5月28日10:21:36  

     /// &lt;/summary&gt;  

     public class ProvideDate  

     {  

         public static List&lt;Customer&gt; GetAllCustomerList()  

         {  

             List&lt;Customer&gt; getcuslist = new List&lt;Customer&gt;();  

             getcuslist.Add(new Customer { CustomerName="JackChen" });  

             getcuslist.Add(new Customer { CustomerName = "Arrmy" });  

             getcuslist.Add(new Customer { CustomerName = "SunSkyUnion" });  

             getcuslist.Add(new Customer { CustomerName = "西藏拉萨" });  

             getcuslist.Add(new Customer { CustomerName = "甘肃玉门关" });  

             return getcuslist;  

        }  

         public static List&lt;Customer&gt; GetAllCustomerTreeList()  

             getcuslist.Add(new Customer { CustomerName = "markChen" });  

             getcuslist.Add(new Customer { CustomerName = "KaiDun" });  

             getcuslist.Add(new Customer { CustomerName = "GuideInformation" });  

             getcuslist.Add(new Customer { CustomerName = "三门峡函谷关" });  

             getcuslist.Add(new Customer { CustomerName = "嘉峪关" });  

             getcuslist.Add(new Customer { CustomerName = "泰山" });  

             getcuslist.Add(new Customer { CustomerName = "嵩山" });  

         }  

     }   

     public class Customer  

         public string CustomerName { get; set; }  

     } 

页面数据绑定: 

//绑定ListBox数据  

          List&lt;Customer&gt; getcuslist = TestSilverlightOutOfBrowerDemo.Date.ProvideDate.GetAllCustomerList();  

          if (getcuslist != null)  

          {  

              ObservableCollection&lt;Customer&gt; getlist = new ObservableCollection&lt;Customer&gt;();  

              foreach (Customer getcus in getcuslist)  

              {  

                  getlist.Add(getcus);  

              }  

              this.customerListBoxMain.ItemsSource = getlist;  

          }  

          //绑定Treeview数据  

          List&lt;Customer&gt; gettreeviewlist=TestSilverlightOutOfBrowerDemo.Date.ProvideDate.GetAllCustomerTreeList();  

          ObservableCollection&lt;Customer&gt; getviewlist = new ObservableCollection&lt;Customer&gt;();  

          foreach (Customer getcustree in gettreeviewlist)  

           {  

              getviewlist.Add(getcustree);  

           }  

          this.AcceptTreeview.ItemsSource = getviewlist; 

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

using System.Collections.ObjectModel; 

如上即简单实现了一个listbox向一个TreeView中拖拽实现,其实我当初在实现这问题,参考大量资料. 我想说一下个人对这个拖拽实现思路理解.首先我想说的是在整个拖拽过程事件执行过程,

注意:虽然实现了Treeview在Listbox之间拖拽,但真正拖拽事件发生是在TreeViewDragDropTarget和ListBoxDragDropTarget控件中. 不要误认为是ListBox或Treeview本身.

(1)先看看TreeViewDragDropTarget关于Drag事件.

<a target="_blank" href="http://blog.51cto.com/attachment/201201/181910418.png"></a>

分别为Drop,DragOver, DragLeave,DragEnter. 这三个真正执行顺序如下: 

<a target="_blank" href="http://blog.51cto.com/attachment/201201/181917759.png"></a>

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

//附属一个监听事件 ItemsChanged 事件由 IItemContainerGenerator 引发,以通知布局项集合已更改  

this.AcceptTreeview.ItemContainerGenerator.ItemsChanged += new System.Windows.Controls.Primitives.ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);  

事件实现:

void ItemContainerGenerator_ItemsChanged(object sender, System.Windows.Controls.Primitives.ItemsChangedEventArgs e)  

             if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)  

             {  

                 //e.Position获取集合中更改发生的位置  

                 int index = (e.Position.Index + e.Position.Offset);  

                 MessageBox.Show("total:" + this.AcceptTreeview.Items.Count.ToString() + "Index:" + index.ToString());  

                 object obj = this.AcceptTreeview.Items[index];  

                 if (obj != null)  

                 {  

                     TreeViewItem getitem = obj as TreeViewItem;  

                     MessageBox.Show(getitem.Header.ToString());  

                     ListBoxItem getboxitem = obj as ListBoxItem;  

                     MessageBox.Show(getboxitem.Content.ToString());  

                 }  

             }  

         } 

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

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

继续阅读