winforms 上下移动ListViewItems

50pmv0ei  于 2023-05-18  发布在  其他
关注(0)|答案(7)|浏览(101)

我有一个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);
        }
    }

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

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++;
        }

但现在,如果我选择两个最上面的项目(或类似的),他们将切换位置时,我点击按钮向上移动。
第二版**
所有的工作都很好向上移动,如下:

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();
        }

但对于向下运动,我似乎无法正确地理解:

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();
        }

它适用于向下移动单个项目,但当我选择多个项目时,它不起作用。

ff29svar

ff29svar1#

试试这样的方法:

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);
    }
}

基本上只是删除项目,然后插入它上面的地方,它曾经是。ListView会自动处理在插入后按顺序排列的项目,所以不用担心。

    • 编辑:**两个最上面的项目交换的原因是顶部的项目永远不会移动(即我没有实现wrap-around移动)。然而,第二个项目是自由移动的,因此进入列表的顶部。

要解决这个问题,你可以做以下两件事情之一:
1.实施一个环绕式的重组(即顶部项目到底部)
1.如果选中了顶部项目,则禁止任何移动(选中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();
    }
}

编辑二:

静态帮助器实现,无回绕:

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();
        }
    }
}

示例:

MoveListViewItems(sourceListView, MoveDirection.Up);
MoveListviewItems(sourceListview, MoveDirection.Down);
3lxsmp7m

3lxsmp7m2#

为了完成@Jason Larkes的答案,使其正确地支持“向下移动”,请在他提供的MoveListViewItems函数的foreach之前添加这个:

ListViewItem[] itemsToBeMoved = sender.SelectedItems.Cast<ListViewItem>().ToArray<ListViewItem>(); 
IEnumerable<ListViewItem> itemsToBeMovedEnum;
if (direction == MoveDirection.Down)
     itemsToBeMovedEnum = itemsToBeMoved.Reverse();
else
     itemsToBeMovedEnum = itemsToBeMoved;

然后迭代使用:

foreach (ListViewItem item in itemsTobemovedEnum)

而不是原来的foreach。
很管用。@EClaesson -我希望这能克服你在评论中提到的问题。

xlpyo6sf

xlpyo6sf3#

这是带换行的,所以如果你向下移动索引0的项目,它将到达最后一个位置,如果你向上移动最后一个项目,它将在列表的第一个位置:

public static class ListExtensions
    {
        public static void MoveUp<T>(this IList<T> list, int index)
        {
            int newPosition = ((index > 0) ? index - 1 : list.Count - 1);
            var old = list[newPosition];
            list[newPosition] = list[index];
            list[index] = old;
        }

        public static void MoveDown<T>(this IList<T> list, int index)
        {
            int newPosition = ((index + 1 < list.Count) ? index + 1 : 0);
            var old = list[newPosition];
            list[newPosition] = list[index];
            list[index] = old;
        }
    }
tkclm6bt

tkclm6bt4#

带wrap around的代码:

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

    private void MoveListViewItems(ListView sourceListView, MoveDirection direction)
    {
        int dir = (int)direction;

        foreach (ListViewItem lvi in sourceListView.SelectedItems)
        {
            int index = lvi.Index + dir;
            if(index >= sourceListView.Items.Count)
                index = 0;
            else if(index < 0)
                index = sourceListView.Items.Count + dir;

            sourceListView.Items.RemoveAt(lvi.Index);
            sourceListView.Items.Insert(index, lvi);
        }
    }
ubof19bj

ubof19bj5#

private void MoveItems(ListView sender, MoveDirection direction)
    {
        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)
        {                
            bool start = true;
            int first_idx = 0;                
            List<ListViewItem> items = new List<ListViewItem>();

            // ambil data
            foreach (ListViewItem i in sender.SelectedItems)
            {
                if (start)
                {
                    first_idx = i.Index;
                    start = false;
                }
                items.Add(i);
            }

            sender.BeginUpdate();

            // hapus
            foreach (ListViewItem i in sender.SelectedItems) i.Remove();

            // insert
            if (direction == MoveDirection.Up)
            {
                int insert_to = first_idx - 1;
                foreach (ListViewItem i in items)
                {
                    sender.Items.Insert(insert_to, i);
                    insert_to++;
                }                    
            }
            else
            {
                int insert_to = first_idx + 1;
                foreach (ListViewItem i in items)
                {
                    sender.Items.Insert(insert_to, i);
                    insert_to++;
                }   
            }                
            sender.EndUpdate();
        }            
    }

你的回答不太管用,朋友。在这里我的代码工作完美...

mm9b1k5b

mm9b1k5b6#

仅用于完整,基于'Jason Larke'静态助手解决方案:
该解决方案不移动相邻的项目,这可以使用堆栈这样做:

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)
{

Stack aPila = new Stack();
ListViewItem item = default(ListViewItem);
foreach ( item in sender.SelectedItems) {
    aPila.Push(item);
}

for (int iaux = 1; iaux <= aPila.Count; iaux++) {
    {
    item  = (ListViewItem)aPila.Pop();
        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();
    }
}
}
2g32fytz

2g32fytz7#

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

public static void MoveListViewItems(this ListView sender, MoveDirection direction)
{
    if (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))))
    {
        List<ListViewItem> llvi = sender.SelectedItems.Cast<ListViewItem>().ToList();
        foreach (ListViewItem item in direction == MoveDirection.Up ? llvi : llvi.Reverse<ListViewItem>())
        {
            int index = item.Index + (int)direction;
            sender.Items.RemoveAt(item.Index);
            sender.Items.Insert(index, item);
        }
    }
}

在静态帮助器类中使用它。它可以完美地工作在多个移动向上和向下。如果你想往下走,你的清单必须颠倒过来。

相关问题