Moving ListViewItems Up & Down

前端 未结 6 2835
你的背包
你的背包 2021-02-20 16:45

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

相关标签:
6条回答
  • 2021-02-20 17:15

    This one is with wrapping, so if you move item at index 0 down it will come to last position, and if you move last item up it will be first on list:

        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;
            }
        }
    
    0 讨论(0)
  • 2021-02-20 17:15
        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();
            }            
        }
    

    Your answers don't work well fren. Here my code work perfect...

    0 讨论(0)
  • 2021-02-20 17:17

    Only for complete, based on 'Jason Larke' static helper solution:

    That solution don't move adjacent items, that can be done using a Stack so:

    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();
        }
    }
    }
    
    0 讨论(0)
  • 2021-02-20 17:29

    Code with 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);
            }
        }
    
    0 讨论(0)
  • 2021-02-20 17:32

    Just to complete the @Jason Larkes answer to make it support "move down" properly, add this right before the foreach in the MoveListViewItems function he provided:

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

    and then iterate using:

    foreach (ListViewItem item in itemsTobemovedEnum)
    

    instead of the original foreach.

    Works like a charm. @EClaesson - I hope this overcomes the issue you wrote about in the comments.

    0 讨论(0)
  • 2021-02-20 17:34

    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);
    
    0 讨论(0)
提交回复
热议问题