WPF: command parameter for delete command in list

In my view model, I have a list (ObservableCollection) containing elements. In the view, this list is displayed in the ItemsControl . Each line has a Delete button. I want the command after the button to remove an item from the list.

 <ItemsControl ItemsSource="{Binding myList}"> <ItemsControl.ItemTemplate> ... <Button Command="{StaticResource myDeleteCommand}" CommandParameter="???"> Remove item </Button> ... </ItemsControl.ItemTemplate> </ItemsControl> 

What should I pass as a parameter to the command?

  • The item itself ( Binding . )? Then I do not have a link to the list in the team, so I will need to change my model so that each element of the list contains a link back to the list.
  • List? Then I do not have a link to this element.
  • How? Then I need to write MultiConverter, which translates the list plus the item into some kind of custom object. It seems like such a simple task has a lot of overhead.

Any ideas? This seems like a fairly common scenario to me, so I guess there should be some sort of well-established solution to best practice ...

+4
source share
2 answers

I implemented such commands in such a way that I pass the element as a parameter. The team knows which list it should work on. Either through a delegate that calls the Delete method in my ViewModel, or the team gets a list of elements in the constructor.

i.e. Team with delegates

 public sealed class SimpleParameterCommandModel<T> : CommandModel { private readonly Action<T> execute; private readonly Func<T, bool> canExecute; public SimpleParameterCommandModel(string label, string tooltip, Action<T> execute, Func<T, bool> canExecute) : base(appCtx, dataCtx, label, tooltip) { if (execute == null) throw new ArgumentNullException("execute"); this.execute = execute; this.canExecute = canExecute; } ... } 

using:

 private ICommand _DeleteCommand = null; public ICommand DeleteCommand { get { if (_DeleteCommand == null) { _DeleteCommand = new SimpleParameterCommandModel<IEnumerable<DataObjectModel>> ("Delete", "Delete selection from data store", (items) => items.ToList().ForEach(i => DeleteItem(i)), (items) => items != null && items.Count() > 0 && AllowDelete); } return _DeleteCommand; } } public void DeleteItem(DataObjectModel item) { if (item == null) { throw new ArgumentNullException("item"); } myCollection.Remove(item.Object); } 

EDIT: Forgot XAML

 <Button Command="{Binding DeleteCommand, ElementName=...}" CommandParameter="{Binding}"> Remove item </Button> 
+4
source

Firstly, I would process the command in ViewModel. I assume that the list that is used for binding is in the ViewModel, so any code that "works" in this list should also be executed in the ViewModel.

 class MyViewModel { // ... Clipping rest of ViewModel class ... private ObservableCollection<MyObject> mMyList = new ObservableCollection<MyObject>(); private ICommand mMyDeleteCommand; public MyViewModel() { InitializeMyListSomehow(); mMyDeleteCommand = new MyCommandClass( (item) => DeleteItem(item), () => mDeleteCanExecute ); } public ObservableCollection<MyObject> MyList { get { return mMyList; } set { // Some function that updates the value and implements INPC SetProperty("MyList", ref mMyList, value); } } public ICommand MyDeleteCommand { get { return mMyDeleteCommand; } } void DeleteHandler(var item) { int index = mMyList.Remove(item); } } 

Are the items unique? If so, you can pass the item, and the Delete command handler can find the item in the list.

If the elements are not unique, you will need to do a little more logic, depending on the expected result.

Now, in the view, your code will look (note that StaticResource becomes a binding):

 <ItemsControl ItemsSource="{Binding MyList}"> <ItemsControl.ItemTemplate> ... <Button Command="{Binding DataContext.MyDeleteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}" CommandParameter="{Binding}"> Remove item </Button> ... </ItemsControl.ItemTemplate> </ItemsControl> 
+3
source

All Articles