随着桌面系统的推出利用鼠标的拖放(Drag and Drop)操作由于其简单直接受到了越来越多的读者的欢迎为迎合这种趋势越来越多程序员在自己的程序中使用了拖放操作拖放操作方便了程序的使用者但由于拖放操作在程序中的设计工作比较还有点麻烦甚至是一个难点许多程序员对其都有点心有余悸本文就结合微软公司最新的Net程序开发语言C#来全面介绍一下在C#中是如何处理拖放操作的
在本文中我们是通过二个代表组件也是在拖放操作中经常使用到的二个组件TreeView组件和ListView组件之间互相进行拖放操作来说明此类问题的在进行拖放操作之前必须要对进行拖放操作的组件的AllowDrop属性值设定为True因为此属性是确定组件是否可以进行拖放操作的
一.本文中介绍的程序的设计和运行的软件环境
()微软公司视窗服务器版
()Net FrameWork SDK Beta
二.由TreeView组件到ListView组件的拖放操作
要完成此次的拖放操作必须处理好三种事件ItemDragDragEnterDragDrop其中只有第一种事件是在源组件中触发的另外二种事件是在目标组件中触发的其中当用户拖动组件触发ItemDrag事件当拖动数据进入目标组件区域触发DragEnter事件当用户在目标组件区域放置拖动的数据触发DragDrop事件下面就根据拖放操作的操作顺序来详细介绍
()开始拖(Drag)操作
通过DoDragDrop方法拉开了拖放操作的第一步DoDragDrop方法的语法为
DoDragDrop ( object data DragDropEffects allowedEffects ) ;
其中第二个参数来是说明此次拖放操作最后所要实现的效果因为拖放操作有时实现的效果是把源组件中的内容拖到目标组件中这种效果就是Move有时拖放的效果是在目标组件中加入拖动的数据对源组件的内容是没有什么影响的这种效果就是Copy当然无论是Move还是Copy这都要通过具体的编程来实现设定这些效果只是告诉操作系统你进行拖放操作的类型从而为拖放操作设定特定的图标此例中实现开始拖放操作的具体实现代码如下
private void treeView_ItemDrag ( object sender ItemDragEventArgs e )
{
string strItem = eItemToString ( ) ;
//开始进行Drag操作
DoDragDrop ( strItem DragDropEffectsCopy | DragDropEffectsMove ) ;
}
在上面代码中我们定义的拖放数据类型是字符串其实拖放的数据类型可以是很多种的你可以通过修改DoDragDrop方法的第一个参数来设定你所要拖放数据类型譬如位图或者其他什么
()目标组件允许进行拖放操作
既然你已经开始进行拖放操作你还必须告诉你要拖放到的目标组件要接受你所拖放的数据DragEnter事件正好可以处理在下列的代码中我们是通过判断拖放数据类型来确定是否接受拖放如果是字符串则可以否则则不行具体代码如下
private void listView_DragEnter ( object sender DragEventArgs e )
{
//判断是否目前拖动的数据是字符串如果是则拖动符串对目的组件进行拷贝if ( eDataGetDataPresent ( DataFormatsText ) ) eEffect = DragDropEffectsMove ;
else
eEffect = DragDropEffectsNone ;
}
()获得拖放的字符串在目标组件中加入相应的内容
此步的处理过程是十分明确的要分成二步来进行首先要得到拖放的字符串其次是在目标组件中加入以此字符串为标题的项目当然还要在相应的位置了下面就是实现这二步操作的具体代码
private void listView_DragDrop ( object sender DragEventArgs e )
{
string dummy = temp ;
//获得进行Drag操作中拖动的字符串
string s = ( string ) eDataGetData ( dummyGetType ( ) ) ;
s = sSubstring ( sIndexOf ( : ) + )Trim ( ) ;
PositionX = eX ;
PositionY = eY ;
Position = listViewPointToClient ( Position ) ;
//在目标组件中加入以此字符串为标题的项目
listViewItemsAdd ( new ListViewItem ( s ) ) ;
}
此致通过对这三个事件的编程已经完成了由TreeView组件到ListView组件的拖放操作
三.由ListView组件到TreeView组件的拖放操作
由ListView组件到TreeView组件的拖放操作和从TreeView组件到ListView组件相类似也是通过ItemDragDragEnterDragDrop三个事件来处理的具体如下
()开始拖(Drag)操作
这和前者没有什么实质上的区别只是在此次的拖放操作开始之前多加入了一些逻辑判断让程序更稳健的允许实现的代码如下
private void listView_ItemDrag ( object sender ItemDragEventArgs e )
{
//判断是否是鼠标右键按动
if ( eButton == MouseButtonsRight ) return ;
int nTotalSelected = listViewSelectedIndicesCount ;
//判断组件中是否存在项目
if ( nTotalSelected <= ) return ;
IEnumerator selCol = listViewSelectedItemsGetEnumerator ( ) ;
selColMoveNext ( ) ;
ListViewItem lvi = ( ListViewItem )selColCurrent ;
string mDir = ;
for ( int i = ; i < lviSubItemsCount ; i++ ) mDir += lviSubItems[ i ]Text + ;
string str = mDirSubstring ( mDirLength ) ;
if ( str == ) return ;
//对组件中的字符串开始拖放操作
listViewDoDragDrop ( str DragDropEffectsCopy | DragDropEffectsMove ) ;
}
()目标组件允许进行拖放操作
这一步是进行拖放操作最为一致的除非你所要进行拖放的数据类型有改变否则没有必要对源代码进行什么修改具体如下
private void treeView_DragEnter ( object sender DragEventArgs e )
{
//判断是否目前拖动的数据是字符串如果是则拖动符串对目的组件进行拷贝if ( eDataGetDataPresent ( DataFormatsText ) ) eEffect = DragDropEffectsCopy ;
else
eEffect = DragDropEffectsNone ;
}
()获得拖放的字符串在目标组件中加入相应的内容
对于进行拖放操作的不同组件获得其拖放的数据的实现方法是不一样的在本步骤中也不例外但总归大同小异掌握程序设计的步骤和要点加上探索研究的精神这个问题应该能够解决下面是实现此步骤的程序代码
private void treeView_DragDrop ( object sender DragEventArgs e )
{
//获得进行Drag操作中拖动的字符串
string dummy = temp ;
string s = ( string ) eDataGetData ( dummyGetType ( ) ) ;
s = sSubstring ( sIndexOf ( : ) + )Trim ( ) ;
PositionX = eX ;
PositionY = eY ;
Position = treeViewPointToClient ( Position ) ;
TreeNode DropNode = thistreeViewGetNodeAt ( Position ) ;
//在目标组件中加入以此字符串为标题的项目
if ( DropNode != null )
{
TreeNode DragNode = new TreeNode ( s ) ;
treeViewNodesInsert ( DropNodeIndex+ DragNode ) ;
}
}
四. 二个组件进行拖放操作的完整源程序代码(dragdropcs)
在掌握了上面的这些步骤过以后可以得到这二个组件相互进行拖放操作的完整代码和编译后程序的运行界面如下
图二个组件相互进行拖放的程序运行界面
dragdropcs的代码如下
using System ;
using SystemDrawing ;
using SystemCollections ;
using SystemComponentModel ;
using SystemWindowsForms ;
using SystemData ;
//导入程序中使用的命名空间
public class Form : Form
{
private TreeView treeView ;
private Point Position = new Point( ) ;
// bool lv_mdown = false ;
private ListView listView ;
private SystemComponentModelContainer components = null ;
public Form ( )
{
InitializeComponent ( ) ;
//初始化窗体中的各个组件
}
//清除程序中使用到的各种资源
protected override void Dispose ( bool disposing )
{
if ( disposing )
{
if ( components != null )
{
componentsDispose ( ) ;
}
}
baseDispose ( disposing ) ;
}
private void InitializeComponent ( )
{
ListViewItem listViewItem = new ListViewItem ( Item ) ;
ListViewItem listViewItem = new ListViewItem ( Item ) ;
treeView = new TreeView ( ) ;
listView = new ListView ( ) ;
SuspendLayout ( ) ;
//此属性必须设定为真这样才能进行拖放操作treeViewAllowDrop = true ;
treeViewImageIndex = ;
treeViewLocation = new Point ( ) ;
treeViewName = treeView ;
//在TreeView组件中加入初始化的节点
treeViewNodesAdd ( new TreeNode ( 节点 ) );
treeViewNodesAdd ( new TreeNode ( 节点 ) );
treeViewSelectedImageIndex = ;
treeViewSize = new Size ( ) ;
treeViewTabIndex = ;
treeViewDragEnter += new DragEventHandler ( treeView_DragEnter ) ;
treeViewItemDrag += new ItemDragEventHandler ( treeView_ItemDrag ) ;
treeViewDragDrop += new DragEventHandler ( treeView_DragDrop ) ;
//此属性必须设定为真这样才能进行拖放操作listViewAllowDrop = true ;
//在ListView组件中加入项目
listViewItemsAdd ( listViewItem ) ;
listViewItemsAdd ( listViewItem ) ;
listViewLocation = new Point ( ) ;
listViewName = listView ;
listViewSize = new Size ( ) ;
listViewTabIndex = ;
listViewView = ViewList ;
listViewDragDrop += new DragEventHandler ( listView_DragDrop ) ;
listViewDragEnter += new DragEventHandler ( listView_DragEnter ) ;
listViewItemDrag += new ItemDragEventHandler ( listView_ItemDrag ) ;
AutoScaleBaseSize = new Size ( ) ;
ClientSize = new Size ( ) ;
ControlsAdd ( listView );
ControlsAdd ( treeView );
thisMaximizeBox = false ;
thisMinimizeBox = false ;
thisName = Form ;
thisText = 全面掌握C#中的拖放操作 ;
thisResumeLayout ( false ) ;
}
static void Main ( )
{
ApplicationRun ( new Form ( ) ) ;
}
private void treeView_ItemDrag ( object sender ItemDragEventArgs e )
{
string strItem = eItemToString ( ) ;
//开始进行Drag操作
DoDragDrop ( strItem DragDropEffectsCopy | DragDropEffectsMove ) ;
}
private void listView_DragEnter ( object sender DragEventArgs e )
{
//判断是否目前拖动的数据是字符串如果是则拖动符串对目的组件进行拷贝if ( eDataGetDataPresent ( DataFormatsText ) ) eEffect = DragDropEffectsMove ;
else
eEffect = DragDropEffectsNone ;
}
private void listView_DragDrop ( object sender DragEventArgs e )
{
string dummy = temp ;
//获得进行Drag操作中拖动的字符串
string s = ( string ) eDataGetData ( dummyGetType ( ) ) ;
s = sSubstring ( sIndexOf ( : ) + )Trim ( ) ;
PositionX = eX ;
PositionY = eY ;
Position = listViewPointToClient ( Position ) ;
//在目标组件中加入以此字符串为标题的项目
listViewItemsAdd ( new ListViewItem ( s ) ) ;
}
private void listView_ItemDrag ( object sender ItemDragEventArgs e )
{
//判断是否是鼠标右键按动
if ( eButton == MouseButtonsRight ) return ;
int nTotalSelected = listViewSelectedIndicesCount ;
//判断组件中是否存在项目
if ( nTotalSelected <= ) return ;
IEnumerator selCol = listViewSelectedItemsGetEnumerator ( ) ;
selColMoveNext ( ) ;
ListViewItem lvi = ( ListViewItem )selColCurrent ;
string mDir = ;
for ( int i = ; i < lviSubItemsCount ; i++ ) mDir += lviSubItems[ i ]Text + ;
string str = mDirSubstring ( mDirLength ) ;
if ( str == ) return ;
//对组件中的字符串开始拖放操作
listViewDoDragDrop ( str DragDropEffectsCopy | DragDropEffectsMove ) ;
}
private void treeView_DragEnter ( object sender DragEventArgs e )
{
//判断是否目前拖动的数据是字符串如果是则拖动符串对目的组件进行拷贝if ( eDataGetDataPresent ( DataFormatsText ) ) eEffect = DragDropEffectsCopy ;
else
eEffect = DragDropEffectsNone ;
}
private void treeView_DragDrop ( object sender DragEventArgs e )
{
//获得进行Drag操作中拖动的字符串
string dummy = temp ;
string s = ( string ) eDataGetData ( dummyGetType ( ) ) ;
s = sSubstring ( sIndexOf ( : ) + )Trim ( ) ;
PositionX = eX ;
PositionY = eY ;
Position = treeViewPointToClient ( Position ) ;
TreeNode DropNode = thistreeViewGetNodeAt ( Position ) ;
//在目标组件中加入以此字符串为标题的项目
if ( DropNode != null )
{
TreeNode DragNode = new TreeNode ( s ) ;
treeViewNodesInsert ( DropNodeIndex+ DragNode ) ;
}
}
}
五.其他组件的拖放操作
本文虽然对TreeView组件和ListView组件之间的拖放操作进行了详细的介绍对于其他的可以用于拖放操作的组件很多组件的拖放操作的实现方法都和这二种差不多但也有一些组件有一些区别譬如ListBox组件等在进行拖放操作的时候他就没有本文介绍的ItemDrag事件那这怎么办我们是通过一个变通的方法来实现的具体是通过MouseMove事件和MouseDown事件来代替ItemDrag事件其中MouseMove事件主要是起到触发拖放操作的作用MouseDown事件主要是起着判断此次拖放操作是否已经完成的作用对于ListBox组件拖放操作的其他步骤也和上面介绍的二个组件没有什么太大区别由于篇幅的关系ListBox组件和其他不存在ItemDrag事件的组件的拖放操作这里就不一一介绍了相信大家能够搞定
六.总结
对于大多数组件来说掌握了ItemDragDragEnterDragDrop三个事件的解决办法也就掌握了组件间的拖放操作当然还有一些例外的组件但总而言之拖放操作的实现步骤都是一样的解决的思路也是大致一致的由于拖放操作的自身的优点对于程序员来说尽快掌握是十分必要的希望本文介绍的内容能够令你满意