Best Way To Delete Item From Collection in UI

Sep 12, 2011 at 4:35 PM

I am new to Catel (and MVVM) and figure this must be a simple thing to do, but I am having a hard time finding a nice, elegant way to do it:

Let's say I have a window which displays a ListBox of Person objects.  The Person objects are contained in an ObservableCollection<Person> in the window's ViewModel.  Following recommended practice for Catel, I create a UserControl, named PersonEntry, and ViewModel, PersonEntryViewModel, to represent each Person object in the ListBox.  One element in this UserControl is a Button, that when pressed, should remove that person from the collection. 

What is the best way to implement this behavior?  It seems to me that there should be a Command in the PersonEntryViewModel (call it 'DeleteMe'), which is bound to the delete button's Command property.  But then how does the PersonEntryViewModel notify the WindowViewModel that the associated Person should be deleted, without tightly coupling the two together?

Coordinator
Sep 12, 2011 at 5:04 PM

The Catel Examples repository contains an exact example what you want to accomplish. You can download the latest source and check it out, but I will try to explain how you can do this the easiest way.

Assuming you have an observable collection with persons, you should also bind to the SelectedItem of the L istBox. So, basically this is what you should have in view model:

/// <summary>
/// Gets or sets the selected person.
/// </summary>
public Person SelectedPerson
{
    get { return GetValue<Person>(SelectedPersonProperty); }
    set { SetValue(SelectedPersonProperty, value); }
}

/// <summary>
/// Register the SelectedPerson property so it is known in the class.
/// </summary>
public readonly PropertyData SelectedPersonProperty = RegisterProperty("SelectedPerson", typeof(Person), null);

 

Then in your xaml, you do this:

<ListBox ItemsSource="{Binding PersonCollection}" SelectedItem="{Binding SelectedPerson}">

(note: if you are using silverlight, make sure to set the binding of the SelectedItem to TwoWay)

Then, there should be a command on the VM that also contains the PersonCollection and SelectedPerson. This command can simple remove the SelectedPerson from the PersonCollection.

Sep 12, 2011 at 6:02 PM
Edited Sep 12, 2011 at 6:03 PM

Thanks, Geert, for the really quick response.  I had seen the approach you list above, but the part that was throwing me off is that in my actual application, there is no way to select an item in the ListBox - all you can do is add or delete.  I wound up making this work by making the Command in the WindowViewModel to be a Command<Person>.  This way, in the PersonEntry UserControl, the delete button is set up like this:

<Button Content="X" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=DataContext.DeletePersonCommand}" CommandParameter="{Binding Person}"/>

then, the DeletePersonCommandExecuted(Person person) method is given a reference to the actual Person object to delete. 

 

Not the prettiest code in the world, but works and seems to be consistent with MVVM principles.

Coordinator
Sep 12, 2011 at 7:47 PM

Still, what item can you delete? If it is a button in an items control, you can indeed bind the command parameter. Of course you must be using WPF to use such wonderful and powerful binding options :)

I think you did a great job, solving the issue this way. If you have any other questions, don't hesitate to contact us!

Sep 12, 2011 at 7:54 PM

Geert - if I understand your first sentence correctly, you are wondering how the delete button knows which item to pass as the Command Parameter?  The button exists in the PersonEntry UserControl that is basically the DataTemplate for how to display a Person object.  The ListBox ItemTemplate property is set to a DataTemplate that simply houses the UserControl.  So - the delete button's datacontext is the PersonEntryViewModel, not the WindowViewModel.  That is why the CommandParameter can be set to {Binding Person}.

Thanks for the encouraging words.  I have been working in WPF for a couple of years, but just delving into MVVM and Catel.  I learned the hard way that I need to apply better structure to my applications and MVVM seems the way to go with WPF.

Coordinator
Sep 12, 2011 at 7:57 PM

Cool, thanks for the explanation. What we did in some apps (but it's just a GUI feature) is fade the buttons in as soon as you hover an item, but that's just a cool extra that you can provide to your users.

I was once like you: new to WPF and already glad that I could get my head around xaml and the binding possibilities. But after 2 or 3 years I found out the real power of MVVM, and the fact that none of the existing frameworks/toolkits could really solve my issues (such as: what if you have nested user controls, or what if I want to developer a user control using MVVM). At that point I decided to write my own framework (actually, we are with 2 developers) and provide it to the world because we think "our" framework actually solves all mvvm questions you might have.