向上和向下移动ListViewItems

ECl*_*son 8 .net c# winforms

我有一个ListView(WinForms),我想在其中单击按钮上下移动项目.要移动的项目是被检查的项目.因此,如果选择第2,6和9项,当我按下按钮向上移动时,它们将变为1,5和8,并且这些位置上的项目向下移动一步.

我觉得我已经让这个变得不必要地变得复杂了,你可以在下面看到.每个ListViewItem的第二个SubItem是一个数字,代表它在列表中的位置(从1开始).

我责怪以下代码缺乏睡眠和咖啡,但如果你能想出一个更简单的方法来完成这个任务,我将感激不尽.

private void sourceMoveUpButton_Click(object sender, EventArgs e)
    {
        List<Int32> affectedNumbers = new List<Int32>();
        bool foundNonChecked = false;

        List<KeyValuePair<int, ListViewItem>> newList = new List<KeyValuePair<int, ListViewItem>>();

        foreach (ListViewItem item in this.sourceListView.CheckedItems)
        {
            int newNum = int.Parse(item.SubItems[1].Text) - 1;

            if (newNum >= 1)
            {
                foreach (ListViewItem testItem in this.sourceListView.Items)
                {
                    if (int.Parse(testItem.SubItems[1].Text) == newNum && !testItem.Checked)
                    {
                        foundNonChecked = true;
                    }
                }

                if (foundNonChecked)
                {
                    item.SubItems[1].Text = newNum.ToString();
                    affectedNumbers.Add(newNum);
                }
            }
        }

        foreach (ListViewItem item in this.sourceListView.Items)
        {
            int num = int.Parse(item.SubItems[1].Text);

            if (affectedNumbers.Contains(num) && !item.Checked)
            {
                item.SubItems[1].Text = (num + affectedNumbers.Count).ToString();
            }

            newList.Add(new KeyValuePair<int, ListViewItem>(int.Parse(item.SubItems[1].Text), item));
            item.Remove();
        }

        newList.Sort((firstPair, secondPair) =>
            {
                return firstPair.Key.CompareTo(secondPair.Key);
            }
        );

        foreach (KeyValuePair<int, ListViewItem> pair in newList)
        {
            this.sourceListView.Items.Add(pair.Value);
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑 我已将其缩短为以下内容:

foreach (ListViewItem item in this.sourceListView.CheckedItems)
        {
            if (item.Index > 0)
            {
                int newIndex = item.Index - 1;
                this.sourceListView.Items.RemoveAt(item.Index);
                this.sourceListView.Items.Insert(newIndex, item);
            }
        }

        int index = 1;
        foreach (ListViewItem item in this.sourceListView.Items)
        {
            item.SubItems[1].Text = index.ToString();

            index++;
        }
Run Code Online (Sandbox Code Playgroud)

但现在,如果我选择两个最顶级的项目(或类似的),当我点击按钮向上移动时,它们将切换到位.

第二次编辑 所有内容都适用于向上移动,具体如下:

if (this.sourceListView.CheckedItems[0].Index != 0)
        {
            this.sourceListView.BeginUpdate();

            foreach (ListViewItem item in this.sourceListView.CheckedItems)
            {
                if (item.Index > 0)
                {
                    int newIndex = item.Index - 1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex, item);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }
Run Code Online (Sandbox Code Playgroud)

但对于向下运动,我似乎无法做到正确:

if (this.sourceListView.CheckedItems[this.sourceListView.CheckedItems.Count - 1].Index < this.sourceListView.Items.Count - 1)
        {
            this.sourceListView.BeginUpdate();

            foreach (ListViewItem item in this.sourceListView.CheckedItems)
            {
                if (item.Index < this.sourceListView.Items.Count - 1)
                {
                    int newIndex = item.Index + 1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex, item);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }
Run Code Online (Sandbox Code Playgroud)

它适用于移动单个项目,但是当我选择多个项目时,它不会.

Jas*_*rke 13

尝试这样的事情:

foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
    if (lvi.Index > 0)
    {
        int index = lvi.Index - 1;
        sourceListView.Items.RemoveAt(lvi.Index);
        sourceListView.Items.Insert(index, lvi);
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上只是移除项目然后将其插入到以前的位置.ListView会在插入后自动处理重新排列顺序中的项目,因此不必担心.

编辑: 两个最顶层的项目交换的原因是顶部项目永远不会移动(即我没有实现wrap-around移动.但是,第二个项目可以自由移动,因此进入列表的顶部.

要解决此问题,您可以执行以下两项操作之一:

  1. 实施环绕式重组(即顶部项目到底)
  2. 如果选择了顶部项目,则阻止任何移动(检查listview.Items [0] .Selected)

至于文本的重做,只需在原始循环中执行.

环绕式实施:

foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
    int index = lvi.Index > 0 ? lvi.Index - 1 : sourceListView.Items.Count - 1;
    sourceListView.Items.RemoveAt(lvi.Index);
    sourceListView.Items.Insert(index, lvi);

    if (index != sourceListView.Items.Count - 1) //not a wraparound:
    {
        //just swap the indices over.
        sourceListView.Items[index + 1].SubItems[1].Text = (index + 1).ToString();
        lvi.SubItems[1].Text = index.ToString();
    }
    else //item wrapped around, have to manually update all items.
    {
        foreach (ListViewItem lvi2 in sourceListView.Items)
            lvi2.SubItems[1].Text = lvi2.Index.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑2:

静态助手实现,没有环绕:

private enum MoveDirection { Up = -1, Down = 1 };

private static void MoveListViewItems(ListView sender, MoveDirection direction)
{
    int dir = (int)direction;
    int opp = dir * -1;

    bool valid = sender.SelectedItems.Count > 0 &&
                    ((direction == MoveDirection.Down && (sender.SelectedItems[sender.SelectedItems.Count - 1].Index < sender.Items.Count - 1))
                || (direction == MoveDirection.Up && (sender.SelectedItems[0].Index > 0)));

    if (valid)
    {
        foreach (ListViewItem item in sender.SelectedItems)
        {
            int index = item.Index + dir;
            sender.Items.RemoveAt(item.Index);
            sender.Items.Insert(index, item);

            sender.Items[index + opp].SubItems[1].Text = (index + opp).ToString();
            item.SubItems[1].Text = (index).ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

MoveListViewItems(sourceListView, MoveDirection.Up);
MoveListviewItems(sourceListview, MoveDirection.Down);
Run Code Online (Sandbox Code Playgroud)