Lorsque l'on souhaite développer une application de gestion, l'une des premières tâches effectuées est la liaison de données entre une collection(d'objet métier) et des contrôles visuelles: une liste déroulante, une liste de données. Il est alors possible de faire des modifications de données à deux niveaux : Soit via le contrôle visuelle, soit via la stucture de données liée directement.
Une chose intéressante dans le DataBinding c'est sa bidirectionnalité à savoir que si nous modifions les données liées au contrôle par son intermédiaire, la structure de données sous-jacente est modifiée et inversemement.
Nous regarderons donc comment faire en sorte que, lorsque l'on modifie nos données métier, les contrôles sont automatiquement mis à jour.
Ce post fait suite à un précédent concernant le Databinding en WPF que vous trouerez ici
Première étape: notre application WPF
Notre application affiche des personnes qui ont été ajoutées dans une collection elle même liée à une listbox.
Deux boutons permettent d'interagir avec la liste:
- Insert : Ajoute une nouvelle personne dans la liste,
- Modification : Modifie le premier élément de la liste en changeant le texte "Myamoto" en "Samouraï Musashi".
Seconde étape: la strucutre de données
Pour réaliser notre application nous allons nous appuyer sur deux classes :
- Personne : correspondant à une personne,
- PersonneCollection : Correspondant à une collection de personne (collection typée donc).
La classe personne est comme suit :
public class Person :
{
private string surname;
public string Surname
{
get
{
return surname;
}
set
{
surname = value;
}
}
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private string adress;
public string Adress
{
get
{
return adress;
}
set
{
adress = value;
}
}
public Person()
{
}
}
La classe PersonneCollection est comme suit :
public class PersonCollection : Collection<Person>
{
}
Troisième étape : le code de la fenêtre
<Window x:Class="WpfApplicationDataBindingPart2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplicationDataBindingPart2"
Title="Liste de personnes" Height="300" Width="300"
Loaded="Window_Loaded">
<Window.Resources>
<local:PersonCollection x:Key="Persons">
<local:Person Name="Myamoto" Surname="Musashi" Adress="Bewise" />
<local:Person Name="Delta" Surname="Kosh" Adress="Bewise" />
<local:Person Name="Lolo" Surname="Suchii" Adress="Bewise" />
</local:PersonCollection>
<DataTemplate x:Key="dtPerson">
<StackPanel>
<TextBlock Text="{Binding Path=Name}" FontSize="14" FontWeight="Bold" />
<TextBlock Text="{Binding Path=Surname}" />
<TextBlock Text="{Binding Path=Adress}" />
</StackPanel>
</DataTemplate>
<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="2" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75*" />
<RowDefinition Height="25*" />
</Grid.RowDefinitions>
<Border BorderBrush="DarkGoldenrod" BorderThickness="3" Grid.Row="0">
<ListBox x:Name="lstPerson" ItemsSource="{Binding}"
DataContext="{StaticResource Persons}"
ItemTemplate="{StaticResource dtPerson}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"/>
</Border>
<StackPanel Grid.Row="1">
<Button x:Name="btInsert" Content="Insert"
Width="120" Height="20"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2"
Click="btInsert_Click"/>
<Button x:Name="btModify" Content="Modification"
Width="120" Height="20"
HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="2"
Click="btModify_Click"/>
</StackPanel>
</Grid>
</Window>
Je ne rentre pas trop dans le détail voici un focus sur les points importants :
- L'instanciation de la collection personne faite de cette façon :
<local:PersonCollection x:Key="Persons">
<local:Person Name="Myamoto" Surname="Musashi" Adress="Bewise" />
<local:Person Name="Delta" Surname="Kosh" Adress="Bewise" />
<local:Person Name="Lolo" Surname="Suchii" Adress="Bewise" />
</local:PersonCollection>
- Le Binding dans la listbox :
<ListBox x:Name="lstPerson" ItemsSource="{Binding}"
DataContext="{StaticResource Persons}"
ItemTemplate="{StaticResource dtPerson}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"/>
Notre souci est donc comment faire réagir le contrôle listbox dés lors que l'on :
- Ajoute un élément dans la ListBox,
- Modifie les propriétés d'une personne de la liste en question.
Quatrième étape : Faire réagir le contrôle à l'ajout d'un élément de notre liste
Pour notifier et rafraichir notre contrôle lors de l'ajout d'un élément dans notre liste, il faut que notre collection personnalisée hérite d'une interface nommée INotifyCollectionChanged. Cette interface va nous permettre d'implémenter un évènement que l'on déclenchera lors de l'ajout et la suppression d'élément dans notre liste. Le code de notre collection devient donc :
public class PersonCollection : Collection<Person>, INotifyCollectionChanged
{
public void Add(Person item)
{
base.Add(item);
ExecuteCollectionChanged(NotifyCollectionChangedAction.Add, item);
}
public void Remove(Person item)
{
base.Remove(item);
ExecuteCollectionChanged(NotifyCollectionChangedAction.Remove, item);
}
void ExecuteCollectionChanged(NotifyCollectionChangedAction action, Person item)
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item));
}
}
#region INotifyCollectionChanged Members
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endregion
}
Une fois cette interface implémentée sur notre liste, L'interface réagit lors du click sur insert et le nouvel élément s'affiche à l'écran. le code du bouton insert est le suivant :
private void btInsert_Click(object sender, RoutedEventArgs e)
{
PersonCollection people = this.Resources["Persons"] as PersonCollection;
people.Add(new Person { Name = "Mim", Surname = "Mimetis", Adress = "Bewise" });
}
Le résultat de l'affichage après l'ajout de MIM dans la liste :
Cinquième étape : Faire réagir le contrôle à la modification d'une propriété d'un élément de la liste
De la même manière, nous souhaitons faire réagir notre contrôle dés que nous modifions une propriété d'une personne de la liste. Pour cela, comme pour notre collection, nous devons utiliser une interface implémentée par notre classe Personne. Elle se nomme : INotifyPropertyChanged. une fois implémenté, notre classe personne est la suivante :
public class Person : INotifyPropertyChanged
{
private string surname;
public string Surname
{
get
{
return surname;
}
set
{
if (value != surname)
{
surname = value;
NotifyPropertyChanged("Surname");
}
}
}
private string name;
public string Name
{
get
{
return name;
}
set
{
if (value != name)
{
name = value;
NotifyPropertyChanged("Name");
}
}
}
private string adress;
public string Adress
{
get
{
return adress;
}
set
{
if (value != adress)
{
adress = value;
NotifyPropertyChanged("Adress");
}
}
}
public Person()
{
}
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
Nous déclenchons donc l'évènement de notification de changement à chaque fois qu'une propriété est modifiée. Le code suivant du bouton "Modification" est donc désormais fonctionnel et chaque changement met à jour la listbox.
Le code du bouton Modification est le suivant :
private void btModify_Click(object sender, RoutedEventArgs e)
{
PersonCollection people = this.Resources["Persons"] as PersonCollection;
Person musashi = people[0] as Person;
musashi.Name = "Samouraï Musashi";
}
Le résultat de la modification est là :
Sixième étape : remarque sur les collections
Nous avons, pour bien comprendre le mécanisme de notification, utiliser une collection personnalisée pour réaliser le DataBinding. Il faut savoir que WPF met à notre disposition une collection générique qui hérite déjà de INotifyCollectionChanged c'est l' ObservableCollection<T>. Celle - ci nous permet donc de nous passer de PersonnCollection. Elle se déclare de la façon suivante
ObservableCollection<Person> people;
Dans le prochain Post sur le DataBinding nous analyserons les BindingExpression et regarderons sur un cas concret comment mettre en oeuvre le DataBinding de manière efficace et performante
Musa.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :