John the Ripper
John the Ripper

Reputation: 2439

How to have a button in a datagrid template that will remove the item when clicked

I would like to use a datatemplate for my datagrid columns and have a button for each item. I would like the item to be removed if the user clicks the button. I am using the MVVM pattern. How would I accomplish this?

<DataGridTemplateColumn>
  <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
      <Button Width="50" Content="Remove" Command="{Binding RemoveItemCommand}"/>
    </DataTemplate>
  </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Upvotes: 6

Views: 1430

Answers (3)

user1228
user1228

Reputation:

The View is responsible for this. You can simply use codebehind to control the visibility of UI elements in response to user actions in the UI.

Sometimes, it is better to be practical than be rigidly dogmatic.


Well, now that you have edited your question, it becomes a completely different matter.

Your DataGrid should be bound to a collection of items.

Your button should be bound to a command on the ViewModel, and the CommandParameter should be the Model that particular row is bound to.

<DataTemplate>
      <Button Content="Remove" 
              Command="{Binding DataContext.RemoveItemCommand, 
                                ElementName=theWindow}"
              CommandParameter="{Binding}" />
</DataTemplate>

Note some important things here. We need, from within the template, to bind to an ICommand on the ViewModel. The ViewModel is the DataContext of the Window. In this example, the window is named 'theWindow' (x:Name="theWindow"). Since the source of the Binding is the window, the Path must point to the ViewModel in the DataContext property on that Window.

We pass the current Model the DataGrid row is bound to into the command. This way, it is triival to remove it from the collection in the ViewModel.

public ObservableCollection<Model> Items {get;set;}

public ICommand RemoveItemCommand {get;set;}

// this method is called when RemoveItemCommand.Execute is called!
public void Execute(object parameter)
{
  Items.Remove(parameter as Model);
}

This assumes you're using one of the standard delegated ICommand implementations out there. You can see how this is trivial to implement, and since the collection is an observable one, once you click the button and the Model is removed, the DataGrid will be notified of the change in the collection and remove that row.

Upvotes: 4

RMart
RMart

Reputation: 548

public class ItemViewModel
{
  public ItemViewModel()
  {
    RemoveCommand = new MyCommand(Remove);
  }

  public event EventHandler ItemRemoved;
  public ICommand RemoveCommand { get; private set; }

  private void Remove()
  {
    // Whatever it takes to remove item from your data store
    service.Remove(this.Data);

    var removeItem = ItemRemoved;
    if (removeItem != null)
      removeItem(this, EventArgs.Empty);
  }
}

public class ListViewModel
{
  public ListViewModel(IEnumerable<ItemViewModel> items)
  {
    ItemVMs=new ObservableCollection<ItemViewModel>(items);
    foreach (var item in ItemVMs)
      item.ItemRemoved += RemoveSelectedItem;
  }

  public ObservableCollection<ItemViewModel> ItemVMs { get; private set; }

  private void RemoveSelectedItem(object sender, EventArgs e)
  {
    var item = sender as ItemViewModel;
    item.ItemRemoved -= RemoveSelectedItem;
    ItemVMs.Remove(item);
  }
}

Each item's RemoveCommand would be bound to its button in your DataGrid. It sounds like you already have that part done. Make the ListViewModel's ItemVMs property the data source for your DataGrid.

Upvotes: 4

Stewbob
Stewbob

Reputation: 16899

You're probably better off using the standard routed events on the Click event of the button instead of a Command. The click event will allow you to retrieve the information about what control was clicked, and then you can also easily retrieve the parent of the button, to delete that item.

Upvotes: 2

Related Questions