使用拖放重新排序winforms列表框?

时间:2009-04-30 02:42:04

标签: c# winforms listbox

这是一个简单的过程吗?

我只是为内部工具编写一个快速的hacky UI。

我不想花一点时间。

5 个答案:

答案 0 :(得分:77)

这是一个快速下来的脏应用程序。基本上我用一个按钮和一个ListBox创建了一个Form。单击按钮时,ListBox将填充接下来20天的日期(必须使用仅用于测试的内容)。然后,它允许在ListBox中拖放以进行重新排序:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.listBox1.AllowDrop = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i <= 20; i++)
            {
                this.listBox1.Items.Add(DateTime.Now.AddDays(i));
            }
        }

        private void listBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.listBox1.SelectedItem == null) return;
            this.listBox1.DoDragDrop(this.listBox1.SelectedItem, DragDropEffects.Move);
        }

        private void listBox1_DragOver(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Move;
        }

        private void listBox1_DragDrop(object sender, DragEventArgs e)
        {
            Point point = listBox1.PointToClient(new Point(e.X, e.Y));
            int index = this.listBox1.IndexFromPoint(point);
            if (index < 0) index = this.listBox1.Items.Count-1;
            object data = e.Data.GetData(typeof(DateTime));
            this.listBox1.Items.Remove(data);
            this.listBox1.Items.Insert(index, data);
        }

答案 1 :(得分:6)

晚了7年。但对于任何新人来说,这是代码。

private void listBox1_MouseDown(object sender, MouseEventArgs e)
    {
        if (this.listBox1.SelectedItem == null) return;
        this.listBox1.DoDragDrop(this.listBox1.SelectedItem, DragDropEffects.Move);
    }

    private void listBox1_DragOver(object sender, DragEventArgs e)
    {
        e.Effect = DragDropEffects.Move;
    }

    private void listBox1_DragDrop(object sender, DragEventArgs e)
    {
        Point point = listBox1.PointToClient(new Point(e.X, e.Y));
        int index = this.listBox1.IndexFromPoint(point);
        if (index < 0) index = this.listBox1.Items.Count - 1;
        object data = listBox1.SelectedItem;
        this.listBox1.Items.Remove(data);
        this.listBox1.Items.Insert(index, data);
    }

    private void itemcreator_Load(object sender, EventArgs e)
    {
        this.listBox1.AllowDrop = true;
    }

答案 2 :(得分:3)

如果你从未实施过拖放,第一次需要几个小时,想要正确完成并且必须阅读文档。特别是如果用户取消操作,立即反馈和恢复列表需要一些想法。将行为封装到可重用的用户控件中也需要一些时间。

如果您从未完成拖放操作,请查看MSDN中的drag and drop example。这将是一个很好的起点,它可能需要半天时间让事情发挥作用。

答案 3 :(得分:0)

另一种方法是使用the list-view控件,这是控件资源管理器用来显示文件夹的内容。它更复杂,但实现了项目拖动。

答案 4 :(得分:0)

这依赖于@BFree的以上回答-非常有帮助。
尝试使用该解决方案时遇到错误,因为我在列表框中使用了数据源。仅出于完整性考虑,如果尝试直接将项目删除或添加到列表框中,则会出现此错误:

// Causes error
this.listBox1.Items.Remove(data);

错误: System.ArgumentException:'设置了DataSource属性时,不能修改Item集合。'

解决方案:更新数据源本身,然后重新绑定到您的列表框。 Program.SelectedReports是一个BindingList。

代码:

    private void listboxSelectedReports_DragDrop(object sender, DragEventArgs e)
    {
        // Get the point where item was dropped.
        Point point = listboxSelectedReports.PointToClient(new Point(e.X, e.Y));
        // Get the index of the item where the point was dropped
        int index = this.listboxSelectedReports.IndexFromPoint(point);
        // if index is invalid, put item at the end of the list.
        if (index < 0) index = this.listboxSelectedReports.Items.Count - 1;
        // Get the item's data.
        ReportModel data = (ReportModel)e.Data.GetData(typeof(ReportModel));
     

        // Update the property we use to control sorting within the original datasource
        int newSortOrder = 0;
        foreach (ReportModel report in Program.SelectedReports) {
            // match sorted item on unique property
            if (data.Id == report.Id)
            {
                report.SortOrder = index;
                if (index == 0) {
                    // only increment our new sort order if index is 0
                    newSortOrder += 1;
                }
            } else {
                // skip our dropped item's index
                if (newSortOrder == index) {
                    newSortOrder += 1;
                }
                report.SortOrder = newSortOrder;
                newSortOrder += 1;
            }
        }

        

        // Sort original list and reset the list box datasource.
        // Note:  Tried other things, Reset(), Invalidate().  Updating DataSource was only way I found that worked??
        Program.SelectedReports = new BindingList<ReportModel>(Program.SelectedReports.OrderBy(x => x.SortOrder).ToList());
        listboxSelectedReports.DataSource = Program.SelectedReports;
        listboxSelectedReports.DisplayMember = "Name";
        listboxSelectedReports.ValueMember = "ID";
    }

其他说明: BindingList在此命名空间下:

using System.ComponentModel;

将项目动态添加到列表时,请确保您填充了排序属性。我使用了整数字段“ SortOrder”。

删除项目时,我不必担心更新Sorting属性,因为它会创建一个数字间隔,在我的情况下,YMMV是可以的。

说实话,除了foreach循环之外,还有一种更好的排序算法,但是在我的情况下,我处理的项目数量非常有限。