delphi listview 添加数据 慢_DragListView – 实现在ListView控件中拖拽(拖动)列表项(行)...

很久没有写过WinForm的程序了,这几天整理了下以前写过的几个控件,发现一些比较有用的扩展。今天介绍一个自定义控件DragListView,可以拖拽其中的行,移动它们的位置,从而重新排序。

这个控件适用于使用Details视图显示项的情况。

原理:继承ListView,当点击选中一个列表项时,拖动鼠标时,释放鼠标时,重写相关拖拽方法,实现拖动效果,将选中的列表项插入到拖拽位置。拖动鼠标的过程中,通过判断拖动的数据和位置来设置拖拽的效果。

1、重写如下几个关于拖拽的方法:

OnItemDrag:启动拖拽,设置拖拽的数据和效果。

OnDragEnter:拖拽进入ListView,判断拖拽的数据格式,并设置拖拽的效果。

OnDragOver:拖动经过ListView时,设置拖动的效果,显示拖放位置线。

OnDragDrop:拖拽释放,移动行。

为了判断拖动的方向,还需要重写OnMouseDown,获取鼠标按下时的坐标,和拖拽释放时的坐标进行比较,判断出向上或向下。

2、为了直接拖出来控件就能使用,这里重写了几个属性,设置了默认值。

AllowDrop:指示控件是否可以接受用户拖到它上面的数据。默认为True。

FullRowSelect:指示当项被选中时,其所有子项是否同该项一起突出显示。默认为True。

GridLines:指示是否在项和子项周围显示网格线,仅在“详细信息”视图中显示。默认为True。

View:选择可以显示项的五种不同视图中的一种。默认为Details。

Sorting:指示对项进行排序的方式,默认为None才不会自动排序。

看看效果:

(1)拖拽中:

82719d77ba275fac33b765256aa815e4.png

(2)拖拽释放:

1ff65380e660e8657bdfbba1e48abf46.png

下边看看代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Collections;namespace VeryCodes.Windows.Forms{ public class DragAndDropListView : ListView { #region 私有变量 ///  /// 上一个拖动悬停的项 ///  private ListViewItem lastHoverItem; ///  /// 指示是否允许拖动行重新排序 ///  private bool allowDragRowReorder; ///  /// 上一次鼠标按下时Y轴坐标,用于判断拖动上下方向 ///  private int lastMouseDownY = -1; ///  /// 上一次鼠标按下时X轴坐标,用于判断拖动左右方向 ///  private int lastMouseDownX = -1; ///  /// 拖拽位置线的颜色 ///  private Color lineColor; #endregion #region 公有属性 ///  /// 获取或设置一个值,该值指示是否允许拖动行重新排序。 ///  [Description("指示是否允许拖动行重新排序。")] [Category("DragListView")] [DefaultValue(true)] public bool AllowDragRowReorder { get { return this.allowDragRowReorder; } set { this.allowDragRowReorder = value; } } ///  /// 获取或设置一个值,该值指示控件是否可以接受用户拖到它上面的数据。 ///  [Description("指示控件是否可以接受用户拖到它上面的数据。")] [Category("DragListView")] [DefaultValue(true)] public new bool AllowDrop { get { return base.AllowDrop; } set { base.AllowDrop = value; } } ///  /// 获取或设置一个值,该值指示当项被选中时,其所有子项是否同该项一起突出显示。 ///  [Description("指示当项被选中时,其所有子项是否同该项一起突出显示。")] [Category("DragListView")] [DefaultValue(true)] public new bool FullRowSelect { get { return base.FullRowSelect; } set { base.FullRowSelect = value; } } ///  /// 获取或设置一个值,该值指示是否在项和子项周围显示网格线,仅在“详细信息”视图中显示。 ///  [Description("指示是否在项和子项周围显示网格线,仅在“详细信息”视图中显示")] [Category("DragListView")] [DefaultValue(true)] public new bool GridLines { get { return base.GridLines; } set { base.GridLines = value; } } ///  /// 获取或设置项在控件中的显示方式。 ///  [Description("选择可以显示项的五种不同视图中的一种。")] [Category("DragListView")] [DefaultValue(View.Details)] public new View View { get { return base.View; } set { base.View = value; } } ///  /// 重新设计Sorting属性,原有的属性如果不为None,则不能拖动行变化位置。 ///  [Description("指示对项进行排序的方式。")] [Category("DragListView")] [DefaultValue(View.Details)] public new SortOrder Sorting { get { return SortOrder.None; } set { base.Sorting = SortOrder.None; } } ///  /// 获取或设置拖拽位置线的颜色。 ///  [Description("获取或设置拖拽位置线的颜色。")] [Category("DragListView")] [DefaultValue(View.Details)] public Color LineColor { get { return lineColor; } set { lineColor = value; } } #endregion ///  /// 初始化DragAndDropListView类的一个新实例 ///  public DragAndDropListView() : base() { this.AllowDragRowReorder = true; this.AllowDrop = true; this.FullRowSelect = true; this.GridLines = true; this.View = View.Details; lineColor = Color.Red; this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); } #region 重写方法 ///  /// 当拖拽释放时的处理 ///  ///  protected override void OnDragDrop(DragEventArgs e) { // 不允许拖拽排序,则直接调用重写的基类方法,然后返回。 if (!allowDragRowReorder) { base.OnDragDrop(e); return; } //判断拖拽的数据是否正确 if (!e.Data.GetDataPresent(typeof(DragItemData).ToString()) || ((DragItemData)e.Data.GetData(typeof(DragItemData).ToString())).ListView == null || ((DragItemData)e.Data.GetData(typeof(DragItemData).ToString())).DragItems.Count == 0) { return; } // 获取拖拽的数据 DragItemData data = (DragItemData)e.Data.GetData(typeof(DragItemData).ToString()); // 获取最终悬停的项 Point cp = base.PointToClient(new Point(e.X, e.Y)); ListViewItem dragToItem = base.GetItemAt(cp.X, cp.Y); // 如果没有悬停项,则添加到最后 if (dragToItem == null) { for (int i = 0; i < data.DragItems.Count; i++) { ListViewItem newItem = (ListViewItem)data.DragItems[i]; base.Items.Add(newItem); } } else { // 如果是向下拖拽,则设置拖动的行的Index为拖动到的行的Index+1 int dropIndex = dragToItem.Index; if (this.View == View.Details || this.View == View.List) { if (lastMouseDownY > cp.Y) // 向上 { } else // 向下 { dropIndex++; } } else { if (lastMouseDownX > cp.X) // 向左 { } else //向右 { dropIndex++; } } // 插入拖动的数据到指定的位置 for (int i = data.DragItems.Count - 1; i >= 0; i--) { ListViewItem newItem = (ListViewItem)data.DragItems[i]; base.Items.Insert(dropIndex, newItem); } } // 从拖出ListView中移除数据 if (data.ListView != null) { foreach (ListViewItem itemToRemove in data.ListView.SelectedItems) { data.ListView.Items.Remove(itemToRemove); } } // set the back color of the previous item, then nullify it if (lastHoverItem != null) { lastHoverItem = null; } this.Invalidate(); // call the base on drag drop to raise the event base.OnDragDrop(e); } ///  /// 当拖拽经过项时的处理 ///  ///  protected override void OnDragOver(DragEventArgs e) { // 不允许拖拽排序,则直接调用重写的基类方法,然后返回。 if (!allowDragRowReorder) { base.OnDragOver(e); return; } // 如果被拖拽的数据和预期的数据类型无关联,则不处理,否则设置拖拽效果。 if (!e.Data.GetDataPresent(typeof(DragItemData).ToString())) { e.Effect = DragDropEffects.None; base.OnDragOver(e); return; } if (this.Items.Count > 0) { // 获取拖拽当前悬停的项 Point cp = this.PointToClient(new Point(e.X, e.Y)); ListViewItem hoverItem = this.GetItemAt(cp.X, cp.Y); // 如果鼠标移动到项的外边,但是在ListView区域内,X轴移动 if (hoverItem == null) { if (cp.X < this.Location.X + this.Width && cp.X > this.Location.X) { hoverItem = base.GetItemAt(this.Location.X + 20, cp.Y); } } // 获取当前控件 GDI+ 绘图图面 Graphics g = this.CreateGraphics(); // 如果没有就拖到最后一个 if (hoverItem == null) { e.Effect = DragDropEffects.Move; if (lastHoverItem != null) { lastHoverItem = null; this.Invalidate(); } hoverItem = this.Items[this.Items.Count - 1]; DrawHoverLine(cp, hoverItem, g); base.OnDragOver(e); return; } // 判断拖拽当前是否悬停在一个新的项上,如果是则重绘控件 if (lastHoverItem == null || lastHoverItem != hoverItem) { this.Invalidate(); } // 如果是同一行,则不执行返回 foreach (ListViewItem itemToMove in this.SelectedItems) { if (itemToMove.Index == hoverItem.Index) { e.Effect = DragDropEffects.None; //hoverItem.EnsureVisible(); this.Invalidate(); base.OnDragOver(e); return; } } // 绘制拖动放置线 DrawHoverLine(cp, hoverItem, g); lastHoverItem = hoverItem; // 确保悬浮行是可见的 hoverItem.EnsureVisible(); } // 设置拖动效果 e.Effect = DragDropEffects.Move; // 调用重写的基类方法 base.OnDragOver(e); } ///  /// 当拖拽操作进入控件时的处理 ///  ///  protected override void OnDragEnter(DragEventArgs e) { // 不允许拖拽排序,则直接调用重写的基类方法,然后返回。 if (!allowDragRowReorder) { base.OnDragEnter(e); return; } // 如果被拖拽的数据和预期的数据类型无关联,则不处理,否则设置拖拽效果。 if (!e.Data.GetDataPresent(typeof(DragItemData).ToString())) { e.Effect = DragDropEffects.None; return; } else { e.Effect = DragDropEffects.Move; } // 调用被重写的基类方法。 base.OnDragEnter(e); } ///  /// 当项被拖拽时的处理 ///  ///  protected override void OnItemDrag(ItemDragEventArgs e) { // 不允许拖拽排序,则直接调用重写的基类方法,然后返回。 if (!allowDragRowReorder) { base.OnItemDrag(e); return; } // 触发拖放操作。 base.DoDragDrop(GetDataForDragDrop(), DragDropEffects.Move); // 调用被重写的基类方法。 base.OnItemDrag(e); } ///  /// 当控件失去焦点时的处理 ///  ///  protected override void OnLostFocus(EventArgs e) { // 重新设置选中项的背景,移除“上一个悬停项”的值 this.ResetOutOfRange(); // 重绘 this.Invalidate(); // 调用重写的基类方法 base.OnLostFocus(e); } ///  /// 当拖拽操作离开控件时的处理 ///  ///  protected override void OnDragLeave(EventArgs e) { // 重新设置选中项的背景,移除“上一个悬停项”的值 ResetOutOfRange(); // 重绘 this.Invalidate(); // 调用重写的基类方法 base.OnDragLeave(e); } ///  /// 重写OnMouseDown,获取鼠标按下时的坐标 ///  ///  protected override void OnMouseDown(MouseEventArgs e) { lastMouseDownY = e.Y; lastMouseDownX = e.X; base.OnMouseDown(e); } #endregion #region 私有方法 ///  /// 获取拖拽项 ///  ///  private DragItemData GetDataForDragDrop() { // 创建一个DragItemData类的实例,用于在拖拽过程中进行处理,如项位置变化等 DragItemData data = new DragItemData(this); // 将选中项的副本保存到拖拽项集合中 foreach (ListViewItem item in this.SelectedItems) { data.DragItems.Add(item.Clone()); } return data; } ///  /// ///  private void ResetOutOfRange() { // determine if the previous item exists, // if it does, reset the background and release // the previous item if (lastHoverItem != null) { lastHoverItem = null; } } ///  /// 绘画拖动位置线 ///  ///  ///  ///  private void DrawHoverLine(Point cp, ListViewItem hoverItem, Graphics g) { if (this.View == View.Details || this.View == View.List) { if (lastMouseDownY > cp.Y) // 向上 { g.DrawLine(new Pen(lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y)); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y - 5), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5) }); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y - 5), new Point(this.Bounds.Width - 9, hoverItem.Bounds.Y), new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + 5) }); } else // 向下 { g.DrawLine(new Pen(Color.Red, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + this.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height)); g.FillPolygon(new SolidBrush(Color.Red), new Point[] { new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5) }); g.FillPolygon(new SolidBrush(Color.Red), new Point[] { new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5), new Point(this.Bounds.Width - 9, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(this.Bounds.Width - 4, hoverItem.Bounds.Y + hoverItem.Bounds.Height + 5) }); } } else { if (lastMouseDownX > cp.X) // 向左 { g.DrawLine(new Pen(lineColor, 2), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height)); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + 5) }); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(hoverItem.Bounds.X - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5) }); } else // 向右 { g.DrawLine(new Pen(lineColor, 2), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height)); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + 5) }); g.FillPolygon(new SolidBrush(lineColor), new Point[] { new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width - 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width + 5, hoverItem.Bounds.Y + hoverItem.Bounds.Height), new Point(hoverItem.Bounds.X + hoverItem.Bounds.Width, hoverItem.Bounds.Y + hoverItem.Bounds.Height - 5) }); } } } #endregion #region DragItemData Class ///  /// 用于封装拖拽项 ///  private class DragItemData { #region Private Members ///  /// 所属的DragAndDropListView ///  private DragAndDropListView m_listView; ///  /// 拖拽项集合 ///  private ArrayList m_dragItems; #endregion #region Public Properties ///  /// 获取所属的DragAndDropListView ///  public DragAndDropListView ListView { get { return m_listView; } } ///  /// 获取拖拽项集合 ///  public ArrayList DragItems { get { return m_dragItems; } } #endregion #region Public Methods and Implementation ///  /// 初始化DragAndDropListView类的一个新实例 ///  ///  public DragItemData(DragAndDropListView listView) { m_listView = listView; m_dragItems = new ArrayList(); } #endregion } #endregion }}

里边注释很详细了,如果还有不清楚的请留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值