We discussed how to do CommandBinding 'MouseLeftButtonUp' event to find the selected row in WPF C1DataGrid in our first Blog.

In this blog lets discuss how to remove a row from Wpf C1DataGrid when user clicks on a button that lies in a C1DataGridTemplateColumn within the same row. Here also, the implementation is using MVVM.


Model


Lets create a class Customer that serves as a 'Model':

class Customer : ViewModelBase
{
string _fname,_lname;
Int32 _age;
DateTime _dob;
public Customer()
{ }
public string FirstName
{
get { return _fname; }
set
{
_fname = value;
OnPropertyChanged("FirstName");
}
}
public string LastName
{
get { return _lname; }
set
{
_lname = value;
OnPropertyChanged("LastName");
}
}
public Int32 Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged("Age");
}
}
public DateTime DateOfBirth
{
get { return _dob; }
set
{
_dob = value;
OnPropertyChanged("DateOfBirth");
}
}
}

ViewModelBase


Here's the class ViewModelBase that Customer inherits. Both ViewModel and Model have the ViewModelBase as the base class. ViewModelBase is a class that will notify property changes to the View using INotifyPropertyChanged interface. It has been used only in the ViewModelBase, instead of inheriting it to both ViewModel and Model.

class ViewModelBase : INotifyPropertyChanged
{
public ViewModelBase()
{}
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

DataGridViewModel (ViewModel)


ViewModel has an ObservableCollection of Model class to update the View with the Model class.


class GridViewModel : ViewModelBase
{
ObservableCollection infos;
ICommand _command;
public GridViewModel()
{
CustomerInfo = new ObservableCollection();
CustomerInfo.Add(new Customer
{
FirstName = "Jon",
LastName = "Smith",
Age = 24,
DateOfBirth = new DateTime(1987, 4, 29),
});
}
public ObservableCollection CustomerInfo
{
get { return infos; }
set
{
infos = value;
OnPropertyChanged("CustomerInfo");
}
}
public ICommand RemoveCommand
{
get
{
if (_command == null)
{
_command = new DelegateCommand(CanExecute, Execute);
}
return _command;
}
}
private void Execute(object parameter)
{
int index = CustomerInfo.IndexOf(parameter as Customer);
if (index > -1 && index < CustomerInfo.Count)
{
CustomerInfo.RemoveAt(index);
}
}
private bool CanExecute(object parameter)
{
return true;
}
}

DelegateCommand


It enables the user to hook up UI interactions with code without tightly coupling with two. The controls in the UI aren't intimately aware of the command logic they are connected with, and the command logic is not aware of the controls it will be associated with. Basically RoutedCommands work great in certain scenarios, and are prevalent in WPF. The thing is, routed commands are not always great fit for MVVM development. Because if we use the RoutedCommand, we need to use a CommandBinding somewhere in the UI in order to connect a VisualElement to the respective command. But with the help of DelegateCommand everything is simple. It has 'CanExecute' and 'Execute' callbacks to achieve this.


class DelegateCommand : ICommand
{
Predicate<object> canExecute;
Action<object> execute;
public DelegateCommand(Predicate<object> _canexecute, Action<object> _execute)
: this()
{
canExecute = _canexecute;
execute = _execute;
}
public DelegateCommand()
{}
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
execute(parameter);
}
}

View


The View (xaml) where rows in C1DataGrid get updated based on the ItemsSource updates from the ViewModel. And, each row has a 'Delete' button which invokes the DelegateCommand to delete the SelectedRow in the DataGrid.


<c1:C1DataGrid Name="c1DataGrid1" ItemsSource="{Binding CustomerInfo}" AutoGenerateColumns="False" CanUserAddRows="False">
<c1:C1DataGrid.Columns>
<c1:DataGridBoundColumn Header="First Name" Binding="{Binding Path=FirstName}"/>
 <c1:DataGridBoundColumn Header="Last Name" Binding="{Binding Path=LastName}"/>
<c1:DataGridBoundColumn Header="Date Of Birth" Binding="{Binding Path=DateOfBirth}" Format="MM/dd/yyyy"/>
<c1:DataGridBoundColumn Header="Age" Binding="{Binding Path=Age}"/>
<c1:DataGridTemplateColumn>
  <c1:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Button Content="Delete Record" Command="{Binding Path=DataContext.RemoveCommand,RelativeSource={RelativeSource AncestorType={x:Type c1:C1DataGrid}}}" CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</c1:DataGridTemplateColumn.CellTemplate>
</c1:DataGridTemplateColumn>
</c1:C1DataGrid.Columns>
</c1:C1DataGrid>


Download C# Sample