在 C# Windows 窗体中的同一列表视图控件中重新排序/移动/拖放列表视图项
本文关键字:列表 视图 拖放 排序 新排序 移动 控件 窗体 Windows | 更新日期: 2023-09-27 18:35:33
我在 C# 2008 System Windows 窗体的 LargeIcon 视图中有一个列表视图。现在我想在另一个位置的同一列表视图中移动此 ListView 中的项目 - 我们称之为"拖放"或"项目重新排序"或其他什么。VB 6 能够做到这一点,并在任何列表视图中自动执行此操作。
C# 似乎没有此功能,或者需要先对其进行编码。对于编码,我没有经验,我在互联网上的研究中也没有找到答案。我只发现了一个不起作用的"覆盖程序"。
我不需要任何其他 ListView 控件(如 ObjectListView 或其他控件),也不需要重写过程或创建新的 ListView 控件。我想按原样在Microsoft给出的 ListView 控件中处理它。对此有任何想法。我相信代码将不胜感激我不能自己做,除非它是非常简单的单行。
PS:如果需要移动项目,我需要移动项目的所有属性(文本,标签,图像键,背景色,前景色,名称,工具提示文本等)。我不知道如何做到这一点。我发现的一个提示:它的存在是为了删除一个项目(称为.删除()) 并插入调用的 。插入()。但是有了这些信息,我仍然无法"移动"鼠标完成的项目。我认为列表视图的所有 DragEvents 在这里都起作用,但我不知道如何使用它们以及如何将所选项目(listView1.SelectedItems)复制到正确的位置,并且需要首先获得这个位置。
事实上,Winforms不支持您谈论的功能,而不是C#。C# 与此类功能无关;这是一项 UI 技术功能,而不是语言功能。但是,为了解决这个问题,我们这里几乎没有代码。它支持用于该目的的每个ListViewItem
的 Position
属性(在LargeIcon
视图中)。另一个重要的属性是 AutoArrange
,这应该设置为 false
以使Position
生效。这是代码:
ListViewItem heldDownItem;
Point heldDownPoint;
//MouseDown event handler for your listView1
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
//listView1.AutoArrange = false;
heldDownItem = listView1.GetItemAt(e.X,e.Y);
if (heldDownItem != null) {
heldDownPoint = new Point(e.X - heldDownItem.Position.X,
e.Y - heldDownItem.Position.Y);
}
}
//MouseMove event handler for your listView1
private void listView1_MouseMove(object sender, MouseEventArgs e)
{
if (heldDownItem != null){
heldDownItem.Position = new Point(e.Location.X - heldDownPoint.X,
e.Location.Y - heldDownPoint.Y);
}
}
//MouseUp event handler for your listView1
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
heldDownItem = null;
//listView1.AutoArrange = true;
}
注意:如您所见,我在那里listView1.AutoArrange
了 2 个注释的代码行,如果您想reorder
而不是更改ListViewItem
位置,您可以取消注释这些行。我可以注意到这里有一些闪烁(当您处理 winforms ListView 时这是正常的),因此您应该使用此代码(可以放置在表单构造函数中)来启用DoubleBuffered
:
typeof(Control).GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.SetValue(listView1, true, null);
我们可以使用以下代码来获取按位置排序的项目
SortedDictionary<Tuple<int, int>, string> points = new SortedDictionary<Tuple<int, int>, string>();
string debug1 = "", debug2 = "";
foreach (ListViewItem item in listView1.Items)
{
Tuple<int, int> tp = new Tuple<int,int>(item.Position.Y, item.Position.X);
points.Add(tp, item.Text);
debug1 += item.Text;
}
foreach (KeyValuePair<Tuple<int, int>, string> kvp in points)
{
debug2 += kvp.Value;
}
MessageBox.Show(debug1); //orignal order
MessageBox.Show(debug2); //sort by position
本文中有拖放重新排序的工作示例,或者此处相同。提供的代码还支持插入标记。在文章中的代码下方:
using System;
using System.Drawing;
using System.Windows.Forms;
public class ListViewInsertionMarkExample : Form
{
private ListView myListView;
public ListViewInsertionMarkExample()
{
// Initialize myListView.
myListView = new ListView();
myListView.Dock = DockStyle.Fill;
myListView.View = View.LargeIcon;
myListView.MultiSelect = false;
myListView.ListViewItemSorter = new ListViewIndexComparer();
// Initialize the insertion mark.
myListView.InsertionMark.Color = Color.Green;
// Add items to myListView.
myListView.Items.Add("zero");
myListView.Items.Add("one");
myListView.Items.Add("two");
myListView.Items.Add("three");
myListView.Items.Add("four");
myListView.Items.Add("five");
// Initialize the drag-and-drop operation when running
// under Windows XP or a later operating system.
if (OSFeature.Feature.IsPresent(OSFeature.Themes))
{
myListView.AllowDrop = true;
myListView.ItemDrag += new ItemDragEventHandler(myListView_ItemDrag);
myListView.DragEnter += new DragEventHandler(myListView_DragEnter);
myListView.DragOver += new DragEventHandler(myListView_DragOver);
myListView.DragLeave += new EventHandler(myListView_DragLeave);
myListView.DragDrop += new DragEventHandler(myListView_DragDrop);
}
// Initialize the form.
this.Text = "ListView Insertion Mark Example";
this.Controls.Add(myListView);
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new ListViewInsertionMarkExample());
}
// Starts the drag-and-drop operation when an item is dragged.
private void myListView_ItemDrag(object sender, ItemDragEventArgs e)
{
myListView.DoDragDrop(e.Item, DragDropEffects.Move);
}
// Sets the target drop effect.
private void myListView_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
}
// Moves the insertion mark as the item is dragged.
private void myListView_DragOver(object sender, DragEventArgs e)
{
// Retrieve the client coordinates of the mouse pointer.
Point targetPoint =
myListView.PointToClient(new Point(e.X, e.Y));
// Retrieve the index of the item closest to the mouse pointer.
int targetIndex = myListView.InsertionMark.NearestIndex(targetPoint);
// Confirm that the mouse pointer is not over the dragged item.
if (targetIndex > -1)
{
// Determine whether the mouse pointer is to the left or
// the right of the midpoint of the closest item and set
// the InsertionMark.AppearsAfterItem property accordingly.
Rectangle itemBounds = myListView.GetItemRect(targetIndex);
if ( targetPoint.X > itemBounds.Left + (itemBounds.Width / 2) )
{
myListView.InsertionMark.AppearsAfterItem = true;
}
else
{
myListView.InsertionMark.AppearsAfterItem = false;
}
}
// Set the location of the insertion mark. If the mouse is
// over the dragged item, the targetIndex value is -1 and
// the insertion mark disappears.
myListView.InsertionMark.Index = targetIndex;
}
// Removes the insertion mark when the mouse leaves the control.
private void myListView_DragLeave(object sender, EventArgs e)
{
myListView.InsertionMark.Index = -1;
}
// Moves the item to the location of the insertion mark.
private void myListView_DragDrop(object sender, DragEventArgs e)
{
// Retrieve the index of the insertion mark;
int targetIndex = myListView.InsertionMark.Index;
// If the insertion mark is not visible, exit the method.
if (targetIndex == -1)
{
return;
}
// If the insertion mark is to the right of the item with
// the corresponding index, increment the target index.
if (myListView.InsertionMark.AppearsAfterItem)
{
targetIndex++;
}
// Retrieve the dragged item.
ListViewItem draggedItem =
(ListViewItem)e.Data.GetData(typeof(ListViewItem));
// Insert a copy of the dragged item at the target index.
// A copy must be inserted before the original item is removed
// to preserve item index values.
myListView.Items.Insert(
targetIndex, (ListViewItem)draggedItem.Clone());
// Remove the original copy of the dragged item.
myListView.Items.Remove(draggedItem);
}
// Sorts ListViewItem objects by index.
private class ListViewIndexComparer : System.Collections.IComparer
{
public int Compare(object x, object y)
{
return ((ListViewItem)x).Index - ((ListViewItem)y).Index;
}
}
}
当心你在哪里添加myListView.ListViewItemSorter = new ListViewIndexComparer();
,我在大列表中遇到了性能问题。要解决它,请在添加列表视图项后添加比较器。