In my viewmodel, I have a list (ObservableCollection) containing items. In the view, this list is displayed in an ItemsControl
. In each row, there is a "Delete" button. I want the command behind the button to remove the item from the list.
<ItemsControl ItemsSource="{Binding myList}">
<ItemsControl.ItemTemplate>
...
<Button Command="{StaticResource myDeleteCommand}" CommandParameter="???">
Remove item
</Button>
...
</ItemsControl.ItemTemplate>
</ItemsControl>
What do I pass as the command parameter?
Binding .
)? Then I don't have a reference to the list in the command, so I'd need to change my model such that each list item contains a back-reference to the list.Any ideas? This seems like a fairly common scenario to me, so I guess there must be some well-established best-practice solution...
I've implemented such commands in that way, that I pass the Item as Parameter. The command self knows on which list it should operate. Either trough a delegate that calls a Delete Method in my ViewModel or the command receives the list of items in it's constructor.
i.e. a Command 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;
}
...
}
usage:
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>
First, I would handle the Command in the ViewModel. I assume that the list that is being used for binding is in the ViewModel, so any code that does "work" on that list should also be done 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 could pass the item, and the Delete command handler could look up the item in the list.
If the items are non-unique, you'll have to do a little more logic, depending on the expected outcome.
Now, in the view, your code will look like (notice the 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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With