在C#Windows窗体中的同一ListView控件中重新排序/移动/拖放ListView项目

时间:2013-10-16 13:53:33

标签: c# winforms listview drag-and-drop listviewitem

我在C#2008系统Windows窗体的LargeIcon视图中有一个 ListView 。 现在我想在同一个ListView中移动一个ListView项目在另一个位置 - 让我们称它为“拖放”或“项目重新排序”或其他什么。 VB 6能够做到这一点,并在任何listView中自动执行此操作。

C#似乎没有此功能,或者需要先编码。为了编码,我没有经验,我在互联网上的研究中找不到任何答案。我发现只有“覆盖程序”没有用。

我不需要任何其他ListView控件(如ObjectListView或其他),我不需要覆盖过程或制作新的ListView控件。我想在Microsoft提供的ListView控件中处理它。对此有任何想法。我相信代码会受到高度赞赏 我不能自己做,除非它是一个非常简单的单行。

PS:如果需要移动项目,我需要移动项目的所有属性(text,tag,imagekey,background-color,foreground-color,name,tooltiptext等)。我不知道如何实现这一目标。 我发现了一个提示:存在删除项目(称为 .Remove ())并插入名为 .Insert ()的项目。但是有了这些信息,我仍然无法通过鼠标“移动”物品。 我认为listView的所有 DragEvents 都在这里发挥作用,但我不知道如何使用它们以及如何将所选项目( listView1.SelectedItems )复制到右侧首先获得这个职位的位置和需要。

3 个答案:

答案 0 :(得分:7)

事实上,Winforms而不是C#不支持您所谈论的功能。 C#与这样的功能无关;它是一种UI技术功能,而不是语言功能。但是,要解决这个问题,我们这里的代码很少。它支持每个Position用于此目的的ListViewItem属性(在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而不是更改reorder位置,我会在其中添加2个已注释的代码行ListViewItem可以取消注释这些行。我可以在这里注意到一些闪烁(当你处理winforms ListView时这是正常的),所以你应该使用这段代码(可以放在表单构造函数中)来启用DoubleBuffered

typeof(Control).GetProperty("DoubleBuffered", 
                             System.Reflection.BindingFlags.NonPublic |
                             System.Reflection.BindingFlags.Instance)
               .SetValue(listView1, true, null);

答案 1 :(得分:1)

我们可以使用以下代码来获取按位置排序的项目

type=submit

答案 2 :(得分:1)

this article 或相同的 here 中有拖放重新排序的工作示例。提供的代码也支持插入标记。下面是文章中的代码:

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(); 的位置,我遇到了大列表的性能问题。为了解决这个问题,在添加 ListView 项后添加 Comparer。