Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving an item up and down in a WPF list box

Tags:

c#

wpf

I have a list box with a bunch of values in it. I also have an UP button and a DOWN button. With these buttons, I would like to move the selected item in the list box up/down. I am having trouble doing this.

Here is my code so far:

    private void btnDataUp_Click(object sender, RoutedEventArgs e)
    {

        int selectedIndex = listBoxDatasetValues.SelectedIndex; //get the selected item in the data list

        if (selectedIndex != -1 && selectedIndex != 0) //if the selected item is selected and not at the top of the list
        {
            //swap items here
            listBoxDatasetValues.SelectedIndex = selectedIndex - 1; //keep the item selected
        }


    }

I do not know how to swap the values! Any help would be GREATLY appreciated!

like image 634
DommyCastles Avatar asked Sep 22 '12 03:09

DommyCastles


3 Answers

Since you have populated the listbox by binding to a ObservableCollection using ItemsSource, you cant modify the Items property of the listbox.

ItemsSource can be set only when the Items collection is empty, and Items can be modified only when ItemsSource is null.

Otherwise you will get the error "Operation is not valid while ItemsSource is in use..."

What you have to do, is modify the underlying collection, and because it's an ObservableCollection, the ListBox will reflect the changes.

The following code shows how you can move an item up and down by swapping the item in the collection.

The corresponding XAML just contains a listbox called lbItems and 2 buttons which hook up the eventhandlers.

public partial class MainWindow : Window
{
    private ObservableCollection<string> ListItems = new ObservableCollection<string>  
    { 
        "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"
    };

    public MainWindow()
    {
        InitializeComponent();
        lbItems.ItemsSource = this.ListItems;
    }

    private void up_click(object sender, RoutedEventArgs e)
    {
        var selectedIndex = this.lbItems.SelectedIndex;

        if (selectedIndex > 0)
        {
            var itemToMoveUp = this.ListItems[selectedIndex];
            this.ListItems.RemoveAt(selectedIndex);
            this.ListItems.Insert(selectedIndex - 1, itemToMoveUp);
            this.lbItems.SelectedIndex = selectedIndex - 1;
        }
    }

    private void down_click(object sender, RoutedEventArgs e)
    {
        var selectedIndex = this.lbItems.SelectedIndex;

        if (selectedIndex + 1 < this.ListItems.Count)
        {
            var itemToMoveDown = this.ListItems[selectedIndex];
            this.ListItems.RemoveAt(selectedIndex);
            this.ListItems.Insert(selectedIndex + 1, itemToMoveDown);
            this.lbItems.SelectedIndex = selectedIndex + 1;
        }
    }
}
like image 132
Peter Hansen Avatar answered Nov 08 '22 15:11

Peter Hansen


I make some extension methods for this:

    public static void MoveItemUp<T>(this ObservableCollection<T> baseCollection, int selectedIndex)
    {
        //# Check if move is possible
        if (selectedIndex <= 0)
            return;

        //# Move-Item
        baseCollection.Move(selectedIndex - 1, selectedIndex);
    }

    public static void MoveItemDown<T>(this ObservableCollection<T> baseCollection, int selectedIndex)
    {
        //# Check if move is possible
        if (selectedIndex < 0 || selectedIndex + 1 >= baseCollection.Count)
            return;

        //# Move-Item
        baseCollection.Move(selectedIndex + 1, selectedIndex);
    }

    public static void MoveItemDown<T>(this ObservableCollection<T> baseCollection, T selectedItem)
    {
        //# MoveDown based on Item
        baseCollection.MoveItemDown(baseCollection.IndexOf(selectedItem));
    }

    public static void MoveItemUp<T>(this ObservableCollection<T> baseCollection, T selectedItem)
    {
        //# MoveUp based on Item
        baseCollection.MoveItemUp(baseCollection.IndexOf(selectedItem));
    }

There is no need to know the ListBox for this.

like image 10
MysticEmpires Avatar answered Nov 08 '22 17:11

MysticEmpires


This is the easiest way to do this and it fires all the right events so you don't have to worry about XAML. ObservableCollection has a nice method called

MoveItem(previousIndex, newIndex)

Given that you have a ObservableCollection named DataItemList

public void MoveUp()
{
  var currentIndex = DataItemList.SelectedIndex;

  //Index of the selected item
  if (currentIndex > 0)
  {
    int upIndex = currentIndex - 1;

    //move the items
    DataItemList.MoveItem(upIndex,currentIndex);         
  }
}

For Down you get the index of the preceding item.

Simple as that!

like image 5
MangoCrysis Avatar answered Nov 08 '22 17:11

MangoCrysis