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++。