移动ListViewItems向上和向下 [英] Moving ListViewItems Up & Down

查看:225
本文介绍了移动ListViewItems向上和向下的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ListView(的WinForms),其中我想用一个按钮,点击上下移动项目。要被移动的物品是被检查谁的那些。因此,如果9项2,6和选择,他们将成为1,5和8时,我preSS运动向上按钮和制在那些地方的项目向下移动的步骤。

我觉得我做了这个过于复杂,因为你可以看到下面。每一个ListViewItem的第二个分项目是一个数字至极重presents它的位置在列表中(公历1)。

我责怪睡眠不足和咖啡以下code,但是如果你能想出一个简单的方法来完成这个任务,我会心存感激。

 私人无效sourceMoveUpButton_Click(对象发件人,EventArgs的)
    {
        名单<的Int32> affectedNumbers =新的名单,其中,的Int32>();
        布尔foundNonChecked = FALSE;

        名单< KeyValuePair< INT,ListViewItem的>> newList =新的名单,其中,KeyValuePair< INT,ListViewItem的>>();

        的foreach(在this.sourceListView.CheckedItems ListViewItem的项目)
        {
            INT newNum = int.Parse(item.SubItems [1]。文) -  1;

            如果(newNum> = 1)
            {
                的foreach(ListViewItem的testItem在this.sourceListView.Items)
                {
                    如果(int.Parse(testItem.SubItems [1]。文)== newNum&安培;&安培;!testItem.Checked)
                    {
                        foundNonChecked = TRUE;
                    }
                }

                如果(foundNonChecked)
                {
                    item.SubItems [1]。文= newNum.ToString();
                    affectedNumbers.Add(newNum);
                }
            }
        }

        的foreach(在this.sourceListView.Items ListViewItem的项目)
        {
            INT NUM = int.Parse(item.SubItems [1]。文);

            如果(affectedNumbers.Contains(NUM)及&安培;!item.Checked)
            {
                item.SubItems [1]。文=(NUM + affectedNumbers.Count)的ToString();
            }

            newList.Add(新KeyValuePair< INT,ListViewItem的>(int.Parse(item.SubItems [1]。文),项目));
            item.Remove();
        }

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

        的foreach(KeyValuePair< INT,ListViewItem的>对在newList)
        {
            this.sourceListView.Items.Add(pair.Value);
        }
    }
 

修改 我有短路它归结为以下几点:

 的foreach(在this.sourceListView.CheckedItems ListViewItem的项目)
        {
            如果(item.Index大于0)
            {
                INT newIndex = item.Index  -  1;
                this.sourceListView.Items.RemoveAt(item.Index);
                this.sourceListView.Items.Insert(newIndex,项目);
            }
        }

        INT索引= 1;
        的foreach(在this.sourceListView.Items ListViewItem的项目)
        {
            item.SubItems [1]。文= index.ToString();

            指数++;
        }
 

但现在,如果我选择两个最上面的项目(或类似),他们将切换的地方,当我点击该按钮上移。

第二次修改 一切正常的向上运动与以下内容:

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

            的foreach(在this.sourceListView.CheckedItems ListViewItem的项目)
            {
                如果(item.Index大于0)
                {
                    INT newIndex = item.Index  -  1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex,项目);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }
 

但对于向下运动我似乎无法得到它的权利:

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

            的foreach(在this.sourceListView.CheckedItems ListViewItem的项目)
            {
                如果(item.Index< this.sourceListView.Items.Count  -  1)
                {
                    INT newIndex = item.Index + 1;
                    this.sourceListView.Items.RemoveAt(item.Index);
                    this.sourceListView.Items.Insert(newIndex,项目);
                }
            }

            this.updateListIndexText();

            this.sourceListView.EndUpdate();
        }
 

它适用于移动的单品了,但是当我选择一个以上的,事实并非如此。

解决方案

尝试是这样的:

 的foreach(ListViewItem的LVI在sourceListView.SelectedItems)
{
    如果(lvi.Index大于0)
    {
        INT指数= lvi.Index  -  1;
        sourceListView.Items.RemoveAt(lvi.Index);
        sourceListView.Items.Insert(索引,LVI);
    }
}
 

基本上只是删除了项目,然后上面的地方曾经是将其插入。 ListView控件自动处理的洗牌下了订单的物品插入后,所以不用担心。

编辑: 究其原因这两个最上面的物品交换是在顶端的项目将不会移动(即我还没有实施环绕式的举动。第二项,然而,是免费的移动,从而进入到列表的顶部。

要解决这个问题,你可以做1 2件事情:

  
      
  1. 实施环绕式洗牌(即首个项目进入底部)
  2.   
  3. prevent任何动静,如果上面的项目中选择(检查listview.Items [0] .Selected)
  4.   

对于重新做文字,只是做在原来的循环。

执行与概括的:

 的foreach(ListViewItem的LVI在sourceListView.SelectedItems)
{
    INT指数= lvi.Index> 0? lvi.Index  -  1:sourceListView.Items.Count  -  1;
    sourceListView.Items.RemoveAt(lvi.Index);
    sourceListView.Items.Insert(索引,LVI);

    如果(指数= sourceListView.Items.Count  -  1!)//不是一个概括:
    {
        //刚过互换指数。
        sourceListView.Items [索引+ 1] .SubItems [1]。文=(索引+ 1)的ToString();
        lvi.SubItems [1]。文= index.ToString();
    }
    否则//项目缠,必须手动更新所有项目。
    {
        的foreach(ListViewItem的lvi2在sourceListView.Items)
            lvi2.SubItems [1]。文= lvi2.Index.ToString();
    }
}
 

编辑2:

静态辅助实施,无环绕:

 私人枚举MoveDirection {向上= -1,关闭= 1};

私有静态无效MoveListViewItems(ListView的发件人,MoveDirection方向)
{
    INT DIR =(int)的方向;
    INT OPP = DIR * -1;

    布尔有效= sender.SelectedItems.Count> 0安培;&安培;
                    ((方向== MoveDirection.Down&安培;及(sender.SelectedItems [sender.SelectedItems.Count  -  1] .Index&其中; sender.Items.Count  -  1))
                || (方向== MoveDirection.Up&安培;及(sender.SelectedItems [0] .Index大于0)));

    如果(有效)
    {
        的foreach(在sender.SelectedItems ListViewItem的项目)
        {
            INT指数= item.Index +方向;
            sender.Items.RemoveAt(item.Index);
            sender.Items.Insert(索引项);

            sender.Items [指数+ OPP] .SubItems [1]。文=(指数+ OPP)的ToString();
            item.SubItems [1]。文=(索引)的ToString();
        }
    }
}
 

例如:

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

I have a ListView (WinForms) in which i want to move items up and down with the click of a button. The items to be moved are the ones who are checked. So if item 2, 6 and 9 are selected, they will become 1, 5 and 8 when i press the button for movement upwards and the items that were on those places are moved down a step.

I feel that i have made this unnecessarily complicated, as you can see below. The second SubItem of each ListViewItem is a number wich represents its place in the list (starts on 1).

I blame lack of sleep and coffe for the following code, but if you could figure out a simpler way to complete this task i would be thankful.

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

EDIT I have shorted it down to the following:

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

But now, if i select the two topmost items (or similar) they will switch place when i click the button for upwards movement.

SECOND EDIT Everything works fine for upwards movement with the following:

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

But for downward movement i can't seem to get it right:

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

It works for moving single items down, but when i select more than one, it doesn't.

解决方案

Try something like this:

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

Basically just removes the item then inserts it above of where it used to be. The ListView automatically handles reshuffling the items down the order after an insert so no worries.

Edit: The reason the two topmost items swap is that the top item will never move (i.e I haven't implemented a wrap-around move. The 2nd item, however, is free to move and thus goes to the top of the list.

To resolve this, you can do 1 of 2 things:

  1. Implement a wrap-around reshuffle (i.e top item goes to the bottom)
  2. Prevent any movement if the top item is selected (check listview.Items[0].Selected)

As for the re-doing of the text, just do it in the original loop.

Implementation with wraparound:

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

Edit 2:

Static helper implementation, no wrap-around:

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

Example:

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

这篇关于移动ListViewItems向上和向下的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆