Austinslik's Blog

Sort or delete ListBox Item Wpf

Posted by austinslik on February 23, 2010

This example will show a simple way to delete or sort listbox selectedItem using WPF C#.
Let’s start with creating xaml mark-up that includes a button, a combobox and a listbox. It should look like this

<Window x:Class="CommandBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorLib"
xmlns:local="clr-namespace:CommandBinding"
Title="Window1" Height="308" Width="194"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<ComboBox Width="100" x:Name="_comboBox" SelectedIndex="0" SelectionChanged="_comboBox_SortBySelection" >
<sys:String>Id</sys:String>
<sys:String>FirstName</sys:String>
<sys:String>LastName</sys:String>
</ComboBox>
</StackPanel>
<ListBox x:Name="_listBox" Grid.Row="1">
</ListBox>
</Grid>
</Window>

Notice that the combobox has

<sys:String>Id</sys:String>
<sys:String>FirstName</sys:String>
<sys:String>LastName</sys:String>

This is because it’s a small sample. It can also be done by binding the combobox to an enum.
The

SelectionChanged="_comboBox_SortBySelection"

will be explained shortly. So let’s move on to code behind.
Here we need some data to work with so we’ll start by creating a person object that looks like this

class Person
{
    private readonly int _id;
    private readonly string _firstName;
    private readonly string _lastName;
    public Person(int id, string firstName, string lastName)
    {
        _id = id;
        _firstName = firstName;
        _lastName = lastName;
    }

    public int Id { get{return _id; }}
    public string FirstNam { get{return _firstName; }}
    public string LastName { get{return _lastName;}}
}

And a collection class that will inherit observable collection to collect our person object we’ve just created. It looks like this

class PersonsCollection:ObservableCollection<Person>
{
  public PersonsCollection()
  {
      Add(new Person(5, "A", "B"));
      Add(new Person(3, "A", "B"));
      Add(new Person(2, "A", "B"));
      Add(new Person(6, "A", "B"));
      Add(new Person(1, "A", "B"));
      Add(new Person(4, "A", "B"));
  }
}

You can fill the “A”,”B” with any name of your choice.
Notice the observable collection has the person class in its greater and less than bracket<Person> which in original definition ObservableCollection<T> The T means generic which means we can throw any object in there and it will hold it and allow add,delete, etc more about observableCollection.

So now that we have some data we need to bind it to our listbox i.e. we need to modify our xaml mark-up a little but first we need supply the listboxItemsource with some data in the constructor(this can also done in xaml but i prefer c#) like this

_listBox.ItemsSource = new PersonsCollection();

and in the listbox marp-up would look like this

<ListBox x:Name="_listBox" Grid.Row="1">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" >
                <TextBlock Text="{Binding Path=Id}" xml:space="preserve"/>
                <TextBlock Text="{Binding Path=FirstName}" xml:space="preserve"/>
                <TextBlock Text="{Binding Path=LastName}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Binding is beyond the scope of this tutorial. At this stage if you hit key Ctrl+F5 you should get

Listbox with value to sort

Now we see our data but can’t sort or delete. Let’s start with sorting by initializing a new instance of the System.Window.Input.RoutedUICommand class which takes some information as parameter e.g.
public static RoutedUICommand = new RoutedUICommand(descriptive text for the command,the declared name of the command for serialization, type that is registering the command (which is the class where is’s being instantiated)).

The code will look like this

public static RoutedUICommand SortPerson = new RoutedUICommand("SortPerson","SortPerson", typeof(Window1));

then in the constructor we’ll call on a property commandbindings from a CommadbingsCollection initialized in UIElement class. It is a collection that gets all the CommandBinding objects (that can be executed) associated with the element SortPerson we created. The code looks like this:

CommandBindings.Add(System.Windows.Input.CommandBinding(SortPerson, SortEventEventArgs)).

Notice SortEventEventArgs in the bracket; this is an ExecutedRoutedEventArgs function that is associated with SortPerson. So let’s go ahead and create it

private void SortEventEventArgs(object sender, ExecutedRoutedEventArgs e)
{
ListCollectionView view =
(ListCollectionView)CollectionViewSource.GetDefaultView
(_listBox.ItemsSource);
view.SortDescriptions.Clear();
view.SortDescriptions.Add(
new SortDescription(e.Parameter.ToString(),ListSortDirection.Ascending));
}

Notice the ListCollectionView. Brief explanation: it provides us the features like Navigation, Sorting, Filtering and Grouping. You can see that the listboxItemSource is added to the listcollectionview… that will supply the listcollectionview with data so that we can navigate, sort, filter or group them. Now the last thing we need to do for sorting is to send a command to listcollectionview with a sort criteria to sort with and that can be done by adding a SelectionChanged to combobox and in the event function we will create the command. In xaml mark-up of combobox we will add something like this SelectionChanged=”_comboBox_SortBySelection” which we’ve already done above. Now in the code behind we’ll create an event function that looks like this

private void _comboBox_SortBySelection(object sender, SelectionChangedEventArgs e)
{
    ICommand comand = SortPerson;
    comand.Execute(e.AddedItems[0]);
}

Inside the this function we created a command by creating an instance of ICommand Class and initialized it with the element SortPerson which is an instance of RoutedUICommand. Now we can use its Execute method to pass a sort criteria as a parameter. If an item is selected then the combobox selectionChanged will trigger this command (Comman.Execute(e.AddedItems[0])) to pass the newly selected item to listcollectionview as string to sort with that coloumn. At this point if you hit key Ctrl+F5 you would be able to sort the listbox items.

Now that we can sort the listbox let’s start with delete. Here we don’t have to do much, first create the same kind of RoutedUICommand like the one we created earlier like this

public static RoutedUICommand DeletePerson =
    new RoutedUICommand("DeletePerson", "DeletePerson", typeof(Window1))

and create an event function just like we did above like this

private void DeleteEventArgs(object sender, ExecutedRoutedEventArgs e)
{
Person selectedItem = (Person)e.Parameter;
dataSource.Remove(selectedItem);
}

Now what we are doing here in the function is just casting the received object back to person object (to the type datasource recognises ) so we can remove it from our datasource, don’t forget our data source is the class PersonCollection. We need to add the above function to Commandbindings like we deed with sorting like this

CommandBindings.Add(new System.Windows.Input.CommandBinding(DeletePerson, DeleteEventArgs, CanExecuteEventHandler))

the third parameter “CanExecuteEventHandler” will be explained shortly. Next we will go and modify our xaml a little so the button we created will do something when its clicked and we can achieve by binding (believe me in wpf anything can be bind). In the button mark-up add

Command="local:Window1.DeletePerson" CommandParameter="{Binding ElementName=_listBox, Path=SelectedItem}"

where Window1 is the name of the project class. The button mark-up would look like this

<Button Grid.Row="2" Content="Delete" x:Name="_deleteButton"
            Command="local:Window1.DeletePerson"
            CommandParameter="{Binding ElementName=_listBox, Path=SelectedItem}"/>

To be able to bind the RoutedIUCommand instance we create in the code behind to Command, we have to import the projects

namespace like this xmlns:local="clr-namespace:CommandBinding"

and CommandParameter is to specify the element the command is going to work with and the path(what to notice in the given element ) to selected item. the listbox and its selected item. That’s all to it. Now we can also delete.

Since this Wpf gave us some nice features like CanExecuteRoutedEventArgs which helps to decide if a command can be executed(it’s a Boolean property that returns true or false) lets add it to the delete button so that its only enable when you click on the listboxitem you would like to delete and after that it disables automatically unless an item is selected. So, lets create a function called CanExecuteEventHandler (used as a parameter in commandbindings above) like this


private void CanExecuteEventHandler(object sender, CanExecuteRoutedEventArgs e)
{
    if ((e.CanExecute = e.Parameter != null) && (e.Parameter is Person))
    e.Handled = true;
}

The if statement checks if something is been selected and the selected item is persons object, (that means the command associated to this element can execute) then the handle which if true will enable the element its associated to else false which means the associated element will remain disabled.

That’s all to it.

Full Source code here

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.