ListView 多行拖拽排序

核心代码:修改ListView的属性,及绑定事件

// 初始化listView1.  
private void InitializeListView()
{
    listView1.AllowDrop = true;
    listView1.ListViewItemSorter = new ListViewIndexComparer();
    //初始化插入标记  
    listView1.InsertionMark.Color = Color.Red;
    //  
    listView1.ItemDrag += listView1_ItemDrag;
    listView1.DragEnter += listView1_DragEnter;
    listView1.DragOver += listView1_DragOver;
    listView1.DragLeave += listView1_DragLeave;
    listView1.DragDrop += listView1_DragDrop;
}

// 当一个项目拖拽是启动拖拽操作  
void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
    Dictionary<ListViewItem, int> itemsCopy = new Dictionary<ListViewItem, int>();
    foreach (ListViewItem item in listView1.SelectedItems)
        itemsCopy.Add(item, item.Index);
    listView1.DoDragDrop(itemsCopy, DragDropEffects.Move);
}

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

//像拖拽项目一样移动插入标记  
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;
}

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

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

    // 返回拖拽项  
    Dictionary<ListViewItem, int> items = (Dictionary<ListViewItem, int>)e.Data.GetData(typeof(Dictionary<ListViewItem, int>));
    foreach (var item in items)
    {
        //在目标索引位置插入一个拖拽项目的副本   
        listView1.Items.Insert(index, (ListViewItem)item.Key.Clone());
        // 移除拖拽项目的原文件  
        listView1.Items.Remove(item.Key);
        if (item.Value >= index) index++;
    }
}

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

处理技巧:上述的代码大部分是直接从网上下载的,根据个人的需要做了微调。下载的代码实现单行的拖拽,修改的重点是多行的拖拽。实现这个有两个关键的地方:

listView1_ItemDrag的DoDragDrop里面的传参和listView1_DragDrop事件里面对传递过来的数据的解析。

解决的过程分几步:

1. 传递当前选中的所有行。这里可以通过listView1.SelectedItems获取得到。

2. 传递的所有行执行插入和删除。由于引用的问题,没有直接对listView1.SelectedItems进行foreach操作(Remove对这个对象同样有效。会产生变foreach边修改的情况)。复制到新的集合。

3. 插入的顺序问题。譬如,如果是2、3、6、7插入到4后面,根据顺序执行后,会产生2376的后果,这是因为6在4之后,插入了6后,6以前的长度会增加1。解决方法,碰到6>4的情况,6插入完成之后,4++。

posted @ 2014-05-06 11:22  脸谱匠  阅读(2918)  评论(0编辑  收藏  举报