C# 支持拖放的TreeView控件,文件拖拽大全。

c# winform TreeView控件中实现拖拽的功能

使用Clipboard ,这是一个静态类
1,存数据
if(textBox1.SelectedText != "")  // 如果textbox1中选中的数据不为空
       Clipboard.SetDataObject(textBox1.SelectedText); //则把数据置于剪切板中
2,读数据
    IDataObject iData = Clipboard.GetDataObject();
    //确定数据的格式是否是你想要的
    if(iData.GetDataPresent(DataFormats.Text)) {
       //如果是,那就把它粘贴到textbox2里
       textBox2.Text = (String)iData.GetData(DataFormats.Text); 
    }
    else {
       // 否则
       textBox2.Text = "无法检索数据";
    }
有关Clipboard 类的用法你可以查一下,msdn上有很详细的示例
希望对你有帮助
赞同
0
| 评论


    曾经做过一个Windows Form,需要在TreeView空间中实现拖拽的功能,首先我想介绍一下Windows Form中的TreeView控件:使用 Windows 窗体 TreeView 控件,可以为用户显示节点层次结构,就像在 Windows 操作系统的 Windows 资源管理器功能的左窗格中显示文件和文件夹一样。树视图中的各个节点可能包含其他节点,称为“子节点”。可以按展开或折叠的方式显示父节点或包含子节点的节点。通过将树视图的 CheckBoxes 属性设置为 true,还可以显示在节点旁边带有复选框的树视图。然后,通过将节点的 Checked 属性设置为 true 或 false,可以采用编程方式来选中或清除节点。通过以上的说明,你可能对TreeView控件有了一个初步的了解,在本文中我的目的是向大家演示一下在TreeView中如何实现接点间的拖拽,如何讲一个节点拖拽到另一个节点之下,使其成为目标节点的子节点,同时被拖拽节点的子节点也将一起被拖拽到目标节点之下,并保持其原来的树状结构。
    在Form Load的时候为了完全显示节点,不必一一点开,建议加上如下代码:

        private void frmDrag_Load(object sender, EventArgs e)
         {
            this.treeView1.ExpandAll();
        }
    要实现TreeView的拖拽功能,首先我们必须将其AllowDrop属性设成true,这样就保证了此TreeView的接点是可以被拖拽的。接下来我们为TreeView添加3个事件,它们分别是1.ItemDrag事件(当用户开始拖动节点时发生。)2.DragEnter事件(在将对象拖入控件的边界时发生。)3.DragDrop事件(在完成拖放操作时发生。)
    
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace treeViewDragDrop
{
    public partial class Form1 : Form
    {
        //拖拽的点
        private Point Position = new Point(0, 0);

        public Form1()
        {
            InitializeComponent();
            this.treeView1.ExpandAll();
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {

        }

        private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            //开始拖拽,设定拖拽效果。传递的参数e.Item项目
            //数据data=e.item,拖拽的最终效果为move
            DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            //进入拖拽区间发生,判断是否可以转换成指定的格式来决定是否能够进入此区域。
            if (e.Data.GetDataPresent(typeof(TreeNode)))//是否是真
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }

        }

        private void treeView1_DragDrop(object sender, DragEventArgs e)
        {
            //拖拽结束,Drop放下时执行
            TreeNode myNode = null;
            if (e.Data.GetDataPresent(typeof(TreeNode)))
            {
                myNode = (TreeNode)(e.Data.GetData(typeof(TreeNode)));//拖拽源节点dragNode

            }
            else
            {
                MessageBox.Show("errror!");
            }

            ///处理拖拽
            Position.X = e.X;
            Position.Y = e.Y;
            Position = treeView1.PointToClient(Position);

            //取得拖拽点的数据
            TreeNode dropNode = this.treeView1.GetNodeAt(Position);

            //1.// 1.目标节点不是空。
            //2.目标节点不是被拖拽接点的子节点。
            //3.目标节点不是被拖拽节点本身

            if (dropNode != null 
                //&& dropNode.Parent != myNode.Parent
                && dropNode != myNode)
            {
                TreeNode dragNode = myNode;//缺取得员节点
                myNode.Remove();
                dropNode.Nodes.Add(dragNode);
            }

            // 如果目标节点不存在,即拖拽的位置不存在节点,那么就将被拖拽节点放在根节点之下
            if (dropNode == null)
            {
                TreeNode DragNode = myNode;
                myNode.Remove();
                treeView1.Nodes.Add(DragNode);
            }
        }
    }
}


 #region TreeView Drag/Drop 
 // Constants for the SendMessage() method. 
         private const int WM_HSCROLL = 276; 
         private const int WM_VSCROLL = 277; 
         private const int SB_LEFT = 6; 
         private const int SB_RIGHT = 7; 
         private const int SB_TOP = 6; 
         private const int SB_BOTTOM = 7; 
         [DllImport("user32.dll")] 
         private static extern int SendMessage(IntPtr hWnd, int wMsg, 
                                           int wParam, int lParam); 
  
         // Node being dragged 
         private TreeNode dragNode = null; 
         // Temporary drop node for selection 
         private TreeNode tempDropNode = null; 
  
         private void treeView_DragDrop(object sender, DragEventArgs e) 
         { 
             // Unlock updates 
             DragHelper.ImageList_DragLeave(this.treeView.Handle); 
  
             // Get drop node 
             TreeNode dropNode = this.treeView.GetNodeAt(this.treeView.PointToClient(new Point(e.X, e.Y))); 
  
             // If drop node isn't equal to drag node, add drag node as child of drop node 
             if (this.dragNode != dropNode) 
             { 
                 // Remove drag node from parent 
                 if (this.dragNode.Parent == null) 
                 { 
                     this.treeView.Nodes.Remove(this.dragNode); 
                 } 
                 else 
                 { 
                     this.dragNode.Parent.Nodes.Remove(this.dragNode); 
                 } 
  
                 // Add drag node to drop node 
                 dropNode.Nodes.Add(this.dragNode); 
                 dropNode.ExpandAll(); 
  
                 // Set drag node to null 
                 this.dragNode = null; 
             } 
         } 
  
         private void treeView_DragEnter(object sender, DragEventArgs e) 
         { 
             DragHelper.ImageList_DragEnter(this.treeView.Handle, e.X - this.treeView.Left, 
                 e.Y - this.treeView.Top); 
         } 
  
         private void treeView_DragLeave(object sender, EventArgs e) 
         { 
             DragHelper.ImageList_DragLeave(this.treeView.Handle); 
         } 
  
         private void treeView_DragOver(object sender, DragEventArgs e) 
         { 
             // Compute drag position and move image 
             Point formP = this.PointToClient(new Point(e.X, e.Y)); 
             DragHelper.ImageList_DragMove(formP.X - this.treeView.Left, formP.Y - this.treeView.Top); 
  
             // Get actual drop node 
             TreeNode dropNode = this.treeView.GetNodeAt(this.treeView.PointToClient(new Point(e.X, e.Y))); 
             if (dropNode == null) 
             { 
                 e.Effect = DragDropEffects.None; 
                 return; 
             } 
  
             e.Effect = DragDropEffects.Move; 
  
             // if mouse is on a new node select it 
             if (this.tempDropNode != dropNode) 
             { 
                 DragHelper.ImageList_DragShowNolock(false); 
                 this.treeView.SelectedNode = dropNode; 
                 DragHelper.ImageList_DragShowNolock(true); 
                 tempDropNode = dropNode; 
             } 
  
             // Avoid that drop node is child of drag node  
             TreeNode tmpNode = dropNode; 
             while (tmpNode.Parent != null) 
             { 
                 if (tmpNode.Parent == this.dragNode) e.Effect = DragDropEffects.None; 
                 tmpNode = tmpNode.Parent; 
             } 
  
             Point pt = this.treeView.PointToClient(new Point(e.X, e.Y)); 
             // if mouse is near to the top, scroll up 
             if (pt.Y  < 30) 
             { 
                 // set actual node to the upper one 
                 if (dropNode.PrevVisibleNode != null) 
                 { 
                     dropNode = dropNode.PrevVisibleNode; 
  
                     // hide drag image 
                     DragHelper.ImageList_DragShowNolock(false); 
  
                     SendMessage(treeView.Handle, WM_VSCROLL, SB_TOP, 0); 
  
                     // show drag image 
                     DragHelper.ImageList_DragShowNolock(true); 
  
                 } 
             } 
             // if mouse is near to the bottom, scroll down 
             else if (pt.Y > this.treeView.Size.Height - 30) 
             { 
                 if (dropNode.NextVisibleNode != null) 
                 { 
                     dropNode = dropNode.NextVisibleNode; 
  
                     DragHelper.ImageList_DragShowNolock(false); 
  
                     SendMessage(treeView.Handle, WM_VSCROLL, SB_BOTTOM, 0); 
  
                     DragHelper.ImageList_DragShowNolock(true); 
                 } 
             } 
             // if mouse is near to the left, scroll left 
             else if (pt.X  < 30) 
             { 
                 //dropNode = dropNode.NextVisibleNode; 
  
                 DragHelper.ImageList_DragShowNolock(false); 
  
                 SendMessage(treeView.Handle, WM_HSCROLL, SB_LEFT, 0); 
  
                 DragHelper.ImageList_DragShowNolock(true); 
             } 
             // if mouse is near to the right, scroll right 
             else if (pt.X > this.treeView.Size.Width - 30) 
             { 
                 //dropNode = dropNode.NextVisibleNode; 
  
                 DragHelper.ImageList_DragShowNolock(false); 
  
                 SendMessage(treeView.Handle, WM_HSCROLL, SB_RIGHT, 0); 
  
                 DragHelper.ImageList_DragShowNolock(true); 
             } 
         } 
  
         private void treeView_GiveFeedback(object sender, GiveFeedbackEventArgs e) 
         { 
             if (e.Effect == DragDropEffects.Move) 
             { 
                 // Show pointer cursor while dragging 
                 e.UseDefaultCursors = false; 
                 this.treeView.Cursor = Cursors.Default; 
             } 
             else e.UseDefaultCursors = true; 
         } 
  
         private void treeView_ItemDrag(object sender, ItemDragEventArgs e) 
         { 
             // Get drag node and select it 
             this.dragNode = (TreeNode)e.Item; 
             this.treeView.SelectedNode = this.dragNode; 
  
             // Reset image list used for drag image 
             this.imageListDrag.Images.Clear(); 
             this.imageListDrag.ImageSize = new Size(this.dragNode.Bounds.Size.Width + this.treeView.Indent, this.dragNode.Bounds.Height); 
  
             // Create new bitmap 
             // This bitmap will contain the tree node image to be dragged 
             Bitmap bmp = new Bitmap(this.dragNode.Bounds.Width + this.treeView.Indent, this.dragNode.Bounds.Height); 
  
             // Get graphics from bitmap 
             Graphics gfx = Graphics.FromImage(bmp); 
  
             // Draw node icon into the bitmap 
             gfx.DrawImage(this.imageListTreeView.Images[dragNode.ImageIndex], 0, 0); 
  
             // Draw node label into bitmap 
             gfx.DrawString(this.dragNode.Text, 
                 this.treeView.Font, 
                 new SolidBrush(this.treeView.ForeColor), 
                 (float)this.treeView.Indent, 1.0f); 
  
             // Add bitmap to imagelist 
             this.imageListDrag.Images.Add(bmp); 
  
             // Get mouse position in client coordinates 
             Point p = this.treeView.PointToClient(Control.MousePosition); 
  
             // Compute delta between mouse position and node bounds 
             int dx = p.X + this.treeView.Indent - this.dragNode.Bounds.Left; 
             int dy = p.Y - this.dragNode.Bounds.Top; 
  
             // Begin dragging image 
             if (DragHelper.ImageList_BeginDrag(this.imageListDrag.Handle, 0, dx, dy)) 
             { 
                 // Begin dragging 
                 this.treeView.DoDragDrop(bmp, DragDropEffects.Move); 
                 // End dragging image 
                 DragHelper.ImageList_EndDrag(); 
             } 
         } 
         #endregion 
 

#region TreeView拖动
        private void tvFormel_ItemDrag(object sender, ItemDragEventArgs e)
        {
            TreeNode tn = e.Item as TreeNode;
            //根节点不允许拖放操作
            if ((e.Button == MouseButtons.Left) && (tn != null) && (tn.Parent != null)) 
            {
                this.tvFormel.DoDragDrop(tn, DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
            }
            //DoDragDrop(e.Item, DragDropEffects.Move);
        }

        private void tvFormel_DragEnter(object sender, DragEventArgs e)
        {
             if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode"))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void tvFormel_DragDrop(object sender, DragEventArgs e)
        {
            TreeNode NewNode;
            if (e.Data.GetDataPresent(typeof(TreeNode)))
            {
                Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y));

                TreeNode DestinationNode = ((TreeView)sender).GetNodeAt(pt);

                NewNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");

                DestinationNode.Nodes.Add((TreeNode)NewNode.Clone());

                DestinationNode.Expand();

                //删除已经移动的节点
                NewNode.Remove();

            }
        }
        #endregion

Control.DoDragDrop 方法


拖放操作其实与剪切与粘贴(或复制与粘贴)没有什么不同,只不过它是使用鼠标而不是使用键盘。在这两类操作中,您都会拥有一个来源(也就是您剪切或 复制的对象)以及一个目标(也就是您所粘贴之处)。不论是哪一种操作,在操作期间,都会在内存中存在数据的一份副本。剪切与粘贴会使用到剪贴板,而拖放则 会使用到一个DataObject对象,其实DataObject对象就好比是一个私有剪贴板。

在一个典型的拖放操作中,将会依序引发下列事件:

1.您可以通过调用源控件的DoDragDrop 方法来初始化拖曳操作 。DoDragDrop方法的语法如下所示:

DragDropEffects DoDragDrop(
Object data,
DragDropEffects allowedEffects)DoDragDrop方法会接受下列两个参数:

data参数用来指定所要拖曳(传递)的数据。 
allowedEffects参数用来指定哪些操作(“复制”和/或“移动”)是被允许的。 
一个新的DataObject对象会自动被创建。

2.接下来会引发源控件的GiveFeedback事件。在大多数的情况下,您并不需要去处理GiveFeedback事件,但是如果您想在拖曳期间显示一个自定义的鼠标指针,则可以在GiveFeedback事件处理函数中编写程序代码来完成此项设定。

3.AllowDrop属性被设定成True的任何控件都可以是置放目标。您可以在设计阶段在“属性”窗口中将要作为目标控件的AllowDrop 属性设定成True , 或者是于运行阶段在窗体的Load事件处理函数中将要作为目标控件的AllowDrop属性设定成True。

4.当您将鼠标指针移至任何一个控件的上方时,便会引发该控件的DragEnter 事件 。我们通常会在目标控件的DragEnter事件处理函数 中,使用GetDataPresent 方法去检测所拖曳的数据格式是否适用于目标控件 ,并使用DragEventArgs类型参数的Effect属性来设 定所允许的置放操作。

5.如果用户在一个有效的置放目标上放开鼠标按键,将会引发目标控件的DragDrop 事件 。我们通常会在目标控件的DragDrop事件处理函数中编写程序代码,从DataObject对象撷取数据并将其显示于目标控件中。

关于拖放操作,您还必须注意下列事项:

某些控件具有自定义的特定拖曳事件。例如,ListView与TreeView控件就拥有ItemDrag事件。 
当一项拖曳操作正在执行 的时候,您可以处理QueryContinueDrag事件,该事件会向系统“要求使用权限”来继续执行拖曳操作。当以该方法处理的时候,也是一种对调用 那些对拖曳操作有影响的方法非常恰当的时机。比方说,当鼠标指针停留在TreeView控件上方的时候展开一个TreeNode。 
您也可以定义您自己的DataFormats。做法非常简单,您只需将您的对象指定为SetData方法中的Object参数,同时请确定所指定的对象是可序列化的。 
除此之外,您还可以使用KeyState属性,以便根据拖放操作期间所按下的按键来产生特定效果。举例来说,当Ctrl键被按下时所拖曳的数据通常要进行复制。 
拖曳文字
拖曳操作最简单的实现就是将某一个TextBox控件中的文字移动或复制到另一个TextBox控件中。当然,您也可以使用复制或剪切以及粘贴操作在两个TextBox控件间复制或移动数据,然而使用拖放操作来完成此类操作绝对会更有效率。

程序范例CH8_DemoForm011.cs示范如何在两个TextBox控件间拖曳文字,其功能特性如下所示:图8.10示范如何拖曳文字

如图8.10所示,由于右侧上方TextBox控件的AllowDrop属性被设定成False,因此您无法从左侧的TextBox控件中将文字拖放其中。 
如图8.11所示,由于右侧下方之TextBox控件的AllowDrop属性被设定成True,因此您可以使用拖放方式将左侧TextBox控件中的文字移动至右侧下方的TextBox控件中。 
值得一提的是,如果您持续按Ctrl键,则可以使用拖放方式将左侧TextBox控件的文字复制到右侧下方的TextBox控件中(如图8.12所示)。


 
图8.11通过拖放操作来移动文字



图8.12通过拖放操作来复制文字

程序范例CH8_DemoForm011.cs在拖放操作方面的程序代码如下所示:

// 声明一个常量以便调试在拖曳期间Ctrl键是否被按下。

const byte CtrlMask = 8;

// 替左侧的 TextBox 控件处理 MouseDown 事件。
// 当用户在此控件的范围内按下鼠标按键时便会引发此事件。

private void txtLeft_MouseDown(object sender, MouseEventArgs e)
{
// 如果用户按下鼠标左键。

if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
// 选取文本框中所有的文字。

txtLeft.SelectAll();

// 初始化拖放操作。

txtLeft.DoDragDrop(
txtLeft.SelectedText,
DragDropEffects.Move | DragDropEffects.Copy);

}

}

// 处理右侧下方 TextBox 控件的 DragEnter 事件。
// 当一个对象被拖曳至目标控件的范围内时,就会引发
// 目标控件的 DragEnter 事件。

private void txtLowerRight_DragEnter(object sender, DragEventArgs e)
{
// 检查被拖曳的数据的类型是否适用于目标控件。如果不适用,则拒绝置放。

if (e.Data.GetDataPresent(DataFormats.Text))
{
// 如果在拖曳期间按着 Ctrl 键,则执行复制操作;反之,则执行移动操作。

if ((e.KeyState & CtrlMask) == CtrlMask)
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.Move;
}
}
else
{
e.Effect = DragDropEffects.None;
}

}

// 处理右侧下方 TextBox 控件的 DragDrop 事件。
// 当用户放开鼠标按键时就会引发此事件,并终止拖放操作。

private void txtLowerRight_DragDrop(object sender, DragEventArgs e)
{

txtLowerRight.Text = e.Data.GetData(
DataFormats.Text).ToString();

// 如果 Ctrl 键没有被按下,移除源文字以便营造出移动文字的效果。

if ((e.KeyState & CtrlMask) != CtrlMask)
{

txtLeft.Text = "";

}

}


从以上的程序代码可以看出,我们会在拖放源(也就是左侧的TextBox控件)的MouseDown事件处理函数中判断鼠标按键已经被按下,而且如果用户是按下鼠标左键的话,便会调用DoDragDrop 方法并传递下列两个参数给它以便初始化拖曳操作:

我们使用TextBox控件中被选取的文字作为第一个参数(即data参数)的值,也就是TextBox控件中的文字将成为被拖曳的数据。 
我们将第二个参数(也就是allowedEffects参数)设定成DragDropEffects.Move Or DragDropEffects.Copy,以便允许用户移动或复制。 
我们会于置放目标(也就是右侧下方的TextBox控件)的DragEnter事件处理函数中执行下列处理:

1.先使用GetDataPresent方法来检查被拖曳的数据是否为纯文字(DataFormats.Text)。如果不是纯文字的话,便将 Effect属性设定成DragDropEffects.None表示置放目标不接受数据;如果是纯文字的话,则继续进行后续处理。

2.检查Ctrl键是否被按下。如果Ctrl键被按下的话,便将Effect属性设定成DragDropEffects.Copy,表示复制数据到 置放目标中,此时鼠标指针将会显示成复制指针图标;如果Ctrl键没有被按下的话,便将Effect属性设定成 DragDropEffects.Move,表示移动数据到置放目标中。

我们会于置放目标(也就是右侧下方的TextBox控件)的DragDrop事件处理函数中执行下列处理:

1.使用GetData方法从DataObject对象中提取被拖曳的文字并将它赋给置放目标。

2.判断Ctrl键是否被按下。如果Ctrl键没有被按下,表示要执行移动操作,此时会移除来源文字以便营造出移动文字的效果。

在Windows资源管理器中使用拖放操作来移动或复制文件是大家所惯用的方 式。Windows资源管理器充分支持拖放操作,而且这也是非常多用户 所偏爱的文件使用方式。此外,许多用户非常习惯直接从Windows资源管理器将文件拖放至对应的应用程序中来打开它们。例如,从Windows资源管理 器将一个.doc 文档拖放至Microsoft Word即会将该文档在Microsoft Word中打开。

[[转载者提示】:不要再Visual Studio调试状态测试从浏览器拖拽,结果不灵的。直接找到bin测试,拖拽就可以运行。

因为项目中文件的归属定义在相应的csproj文件中
这个文件中标记的是以项目目录开始的相对位置
你把文件剪切到另一个文件夹,对于项目来说,就会认为这个文件找不到了,拖拽就不灵了。

 



图8.15示范如何从Windows资源管理器中拖放文件

图8.15所示是程序范例CH8_DemoForm013.cs的运行画面。显而易见地,您可以从Windows资源管理器将一个或多个文件拖放至 窗体上的ListBox控件中,而被拖放的文件的文件名会被添加到ListBox控件中。以下是CH8_DemoForm013.cs的程序代码内容:

private void ListBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.All;
}
}

private void ListBox1_DragDrop(object sender, DragEventArgs e)
{
if(e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] MyFiles;
int i;

// 将文件赋给一个数组。

MyFiles = (string[])(e.Data.GetData(DataFormats.FileDrop));

// 循环处理数组并将文件添加到列表中。

for(i = 0;i <= MyFiles.Length - 1;i++)
{
ListBox1.Items.Add(MyFiles[i]);
}
}
}



 

图8.16在两个列表间来回拖放一个或多个文件来移动项目

请注意我们在ListBox控件的DragEnter事件处理函数中将Effect属性设定成DragDropEffects.All。由于文件本 身实际上并没有被移动或复制,因此拖放源如何设定AllowedEffects将无关紧要,设定All表示对任何的FileDrop都会启用置放。

就本范例而言,DataFormats.FileDrop格式会含有每一个被置放文件的完整路径。本范例的操作逻辑是将所有被拖放文件的完整路径添 入ListBox控件中,当然,您可以采用其他方法,比方说,您可以将被拖放的文件在一个MDI(多文件界面)文件窗口中打开。

在两个列表之间来回拖放项目
另外一项常见的拖放需求是,在两个列表(ListView控件)之间来回拖放项目。事实上,我们经常会通过一组 按钮来将列表中被选取的项目移至另外一个列表中,不过这样的操作模式需要两次鼠标按键操作(第一次选取项目,第二次单击按钮)。显然,在这样的操作需求 中,拖放操作会较受青睐,因为它只需单一动作即可完成(选取并拖曳)。

图8.16所示是程序范例CH8_DemoForm014.cs的运行画面。显而易见地,您可以在两个列表间来回拖放一个或多个文件来移动项目。本程序范例的设计重点说明如下:

由于两个列表的ListView控件都可以作为置放目标,因此务必将这两个ListView控件的AllowDrop属性设定成True。 
请将两个ListView控件的MultiSelect属性设定成True。 
请将两个ListView控件的FullRowSelect属性设定成True。 
以下是程序范例CH8_DemoForm014.cs的程序代码内容。于Load事件处理函数中所调用的 PopulateListView() 程序主要是用来初始化两个ListView控件: 
private void CH4_DemoForm067_Load(object sender, EventArgs e)
{
this.PopulateListView();
}

private void ListView_ItemDrag(object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
ListViewItem[] myItems = 
new ListViewItem[((ListView)(sender)).SelectedItems.Count];
int i = 0;

// 循环处理拖放来源的 SelectedItems 集合。

foreach(ListViewItem myItem in 
((ListView)(sender)).SelectedItems)
{
// 将ListViewItem新增至ListViewItems的数组中。

myItems[i] = myItem;
i = i + 1;
}

// 建立一个DataObject对象来包含ListViewItem的数组。

((ListView)(sender)).DoDragDrop(new
DataObject("System.Windows.Forms.ListViewItem()", 
myItems), DragDropEffects.Move);
}

private void ListView_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{

// 检查自定义的 DataFormat ListViewItem 数组。

if (e.Data.GetDataPresent(
"System.Windows.Forms.ListViewItem()"))
{
e.Effect = DragDropEffects.Move;
}
else
{
e.Effect = DragDropEffects.None;
}
}

private void ListView_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
ListViewItem[] myItems =
(ListViewItem[])(
e.Data.GetData("System.Windows.Forms.ListViewItem()"));
int i = 0;

foreach (ListViewItem myItem in myItems)
{
// 将项目添加到目标列表中。

ListViewItem item = new ListViewItem(myItems[i].Text);
item.SubItems.Add(myItems[i].SubItems[1].Text);
((ListView)(sender)).Items.Add(item);

// 从源列表移除项目。

if (sender == ListView1)
{
istView2.Items.Remove(ListView2.SelectedItems[0]);
}
else
{
ListView1.Items.Remove(ListView1.SelectedItems[0]);
}
i = i + 1;
}
}

您或许会觉得奇怪,为什么不使用ListBox控件而要使用ListView控件。最主要的理由是,ListBox控件并不支持拖曳多个项目,单击列表会使得多重选取失效。

ListView与TreeView控件都拥有一个ItemDrag事件来促进拖曳操作。在本范例中,我们使用单一个ItemDrag事件处理函数来处理两个ListView控件的ItemDrag事件。其中的sender参数代表初始化拖曳的控件。

由于DataFormats类的成员并不包括ListViewItem类型,所以数据必须当作一个系统Type来传递。ItemDrag事件处理函 数的程序代码会创建一个类型为ListViewItem的数组并循环处理SelectedItems集合以便添入数组。在DoDragDrop方法中,一 个新的DataObject对象会被创建并以数组来添入。您可以使用相同的技巧来拖放任何的系统Type。

在DragDrop事件处理函数中,我们会将DataObject对象中的数组复制到一个新的ListViewItem数组中,而且每一个ListViewItem会被添加到目标ListView控件的Items集合中。

在两个TreeView之间来回拖放节点

程序范例

图8.17与图8.18所示是程序范例CH8_DemoForm015.cs的运行画面。显而易见地,您可以在两个TreeView控件间来回拖放一个节点(移动或复制)。本程序范例的程序代码如下所示:// 声明一个常量以便侦测在拖曳期间 Ctrl 键是否被按下。

const byte CtrlMask = 8;

// 处理两个 TreeView 控件的 ItemDrag 事件。

private void TreeView_ItemDrag(System.Object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
// 初始化拖放操作。

DoDragDrop(e.Item, 
DragDropEffects.Move | DragDropEffects.Copy);
}
}

// 处理两个 TreeView 控件的 DragDrop 事件。

private void TreeView_DragDrop(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
// 此变量用来持有被用户所拖曳的节点。

TreeNode OriginationNode =
(TreeNode)(
e.Data.GetData("System.Windows.Forms.TreeNode"));

// 为一个TreeView控件调用GetDataPresent方法与为一个文字或图像的方式一点不同,原因是TreeNode并不是 DataFormats类的一个成员。也就是说,它不是一个预先定义的类型。诸如此种状况,您必须使用能够接受一个字符串作为类型的重载版本。

if (e.Data.GetDataPresent(
"System.Windows.Forms.TreeNode", false))
{
Point pt;
TreeNode DestinationNode;

// 取得鼠标指针所在位置的工作区坐标(Client Coordinate)。

pt = ((TreeView)(sender)).PointToClient(
new Point(e.X, e.Y));

// 选取鼠标指针所在位置之下的节点。

DestinationNode = ((TreeView)(sender)).GetNodeAt(pt);

// 此处的 If 语句用来确保当用户在他们尝试去拖曳节点的上方不小心放开鼠标按键的话,不会失去节点。如果您没有去检查目标节点是否就是源节点,将会使得该节点消失。

if (DestinationNode.TreeView != OriginationNode.TreeView)
{
DestinationNode.Nodes.Add(
(TreeNode)(OriginationNode.Clone()));

// 当添加一个新的节点时展开父节点,如此才会清楚地呈现出拖放操作的结果。如果没有这样做的话,将会显示一个 + 号。

DestinationNode.Expand();

// 如果 Ctrl 键没有被按下,就将原来的节点移除
// 以便实现移动节点的拖放操作。

if ((e.KeyState & CtrlMask) != CtrlMask)
{
OriginationNode.Remove();
}
}
}
}

// 处理两个 TreeView 控件的 DragEnter 事件。

private void TreeView_DragEnter(System.Object sender,
System.Windows.Forms.DragEventArgs e)
{
// 检查被拖曳的数据的类型是否适用于目标控件。如果不适用,则拒绝置放。

if (e.Data.GetDataPresent(
"System.Windows.Forms.TreeNode"))
{
// 如果在拖曳期间按着 Ctrl 键,则执行复制操作;反之,则执行移动操作。

if ((e.KeyState & CtrlMask) == CtrlMask)
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.Move;
}
}
else
{
e.Effect = DragDropEffects.None;
}
}

 


图8.17使用拖放操作来移动节点

 


图8.18使用拖放操作来复制节点

 



public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        InitializeListView();
    }
    // 初始化listView1.
    private void InitializeListView()
    {
        listView1.ListViewItemSorter = new ListViewIndexComparer();
        //初始化插入标记
        listView1.InsertionMark.Color = Color.Red;
        //
        listView1.AllowDrop = true;
    }

    // 当一个项目拖拽是启动拖拽操作
    private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
    {
        listView1.DoDragDrop(e.Item, DragDropEffects.Move);
    }

    private void listView1_DragEnter(object sender, DragEventArgs e)
    {
        e.Effect = e.AllowedEffect;
    }

    //像拖拽项目一样移动插入标记
    private void listView1_DragOver(object sender, DragEventArgs e)
    {
        // 获得鼠标坐标
        Point point = listView1.PointToClient(new Point(e.X, e.Y));
        // 返回离鼠标最近的项目的索引
        int index = listView1.InsertionMark.NearestIndex(point);
        // 确定光标不在拖拽项目上
        if (index > -1)
        {
            Rectangle itemBounds = listView1.GetItemRect(index);
            if (point.X > itemBounds.Left + (itemBounds.Width / 2))
            {
                listView1.InsertionMark.AppearsAfterItem = true;
            }
            else
            {
                listView1.InsertionMark.AppearsAfterItem = false;
            }
        }
        listView1.InsertionMark.Index = index;
    }

    // 当鼠标离开控件时移除插入标记
    private void listView1_DragLeave(object sender, EventArgs e)
    {
        listView1.InsertionMark.Index = -1;
    }

    // 将项目移到插入标记所在的位置
    private void listView1_DragDrop(object sender, DragEventArgs e)
    {
        // 返回插入标记的索引值
        int index = listView1.InsertionMark.Index;
        // 如果插入标记不可见,则退出.
        if (index == -1)
        {
            return;
        }
        // 如果插入标记在项目的右面,使目标索引值加一
        if (listView1.InsertionMark.AppearsAfterItem)
        {
            index++;
        }

        // 返回拖拽项
        ListViewItem item = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
        //在目标索引位置插入一个拖拽项目的副本 
        listView1.Items.Insert(index, (ListViewItem)item.Clone());
        // 移除拖拽项目的原文件
        listView1.Items.Remove(item);
    }

    // 对ListView里的各项根据索引进行排序
    private class ListViewIndexComparer : System.Collections.IComparer
    {
        public int Compare(object x, object y)
        {
            return ((ListViewItem)x).Index - ((ListViewItem)y).Index;
        }
    }
}


参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值