Les DataGrid en WPF sont souvent complexes à manipuler. Lorsque l’on cherche à développer un comportement particulier il est coutumes de coder ce comportement dans le Code-behind de la vue qui contient la DataGrid, car c’est souvent le seul lieu où l’on retrouve toutes les informations dont nous avons besoin. Cette solution ne respecte absolument pas le pattern MVVM (en tout cas, bien souvent).
Dans cet article je vous propose une solution au problème de gestion de la suppression de ligne dans une DataGrid depuis la vue. En effet, autoriser la suppression quand l’action vient du ViewModel cela est simple mais quand l’action vient de la vue, c’est plus compliqué. Pour supprimer un élément depuis la vue il suffit d’appuyer sur le bouton DEL pour supprimer l’élément sélectionné, la DataGrid va automatiquement supprimer l’élément de la liste sur laquelle elle est bindée. Il n’est donc pas possible d’intervenir avant la suppression afin d’autoriser ou non celle-ci.
Il est tout à fait possible d’autoriser ou non la suppression tout en respectant le pattern MVVM.
Supposons que nous ayons une vue avec une DataGrid et derrière cela, un ViewModel qui contient notre liste d’élément (une ObservableCollection, hein ?). Pour résoudre le problème nous allons ajouter deux propriétés sur notre ViewModel qui sont les suivantes :
private bool _canRemove;
public bool CanRemove
{
get { return _canRemove; }
set { Set(ref _canRemove, value); }
}
private PersonViewModel _selectedPerson;
public PersonViewModel SelectedPerson
{
get { return _selectedPerson; }
set { Set(ref _selectedPerson, value); }
}
La première est un booléen que l’on va binder sur la propriété de dépendance CanUserDeleteRows de la DataGrid. Cette propriété est un booléen qui permet ou non la suppression des éléments depuis la vue. C’est ce booléen qui va piloter l’autorisation.
La deuxième est l’élément sélectionné de la grille. C’est ici que le principe s’applique, à chaque modification de l’élément sélectionné, on met à jour le booléen CanRemove. Cette action est donc effectuée avant que l’action de suppression ne soit appelée.
Voyons maintenant comment est notre vue :
<Window x:Class="DataGridRemover.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" CanUserDeleteRows="{Binding CanRemove}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
On peut voir qu’il n’y a rien de plus que les trois bindings suivant :
- ItemsSource
- SelectedItem
- CanUserDeleteRows
Dans cette vue, il n’y a aucun Code-behind.
Il ne reste plus qu’un petit bout de code dans le ViewModel à faire et le tour sera joué. C’est ce code qui va mettre à jour le booléen d’autorisation. Il suffit de surcharger la méthode OnPropertyChanged contenue dans votre ViewModel de base (si vous n’avez pas cela, je vous propose une implémentation ici partie 1 et partie 2) :
protected override void OnPropertyChanged(string propertyName)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "SelectedPerson")
{
CanRemove = SelectedPerson != null && SelectedPerson.Name != null && SelectedPerson.Name.Count() > 6;
}
}
Maintenant à chaque fois que l’on sélectionne un élément le booléen est mis à jour pour résoudre le booléen d’autorisation. Et voila le tour est joué !