Windows Forms : de la liaison de données à la liaison d'objets▲
Description de la série d'articles▲
-
correction des lacunes et faiblesses de la liaison de données ;
-
extensions des fonctionnalités de la liaison de données ;
- des liaisons sur les évènementsWindows Forms - de la liaison de données à la liaison d'objets - partie 3 : des liaisons sur les évènements,
- des vues sur les objets (utilisation des champs et autres éléments du modèle objet) ;
-
présentation de la liaison d'objets (conclusion) ;
- présentation du projet permettant d'effectuer la liaison sur les objets et démonstration des conséquences de son utilisation lors du développement d'une application.
Cette section sera mise à jour en fonction de l'avancement de la série.
Les preuves de faisabilité (le code)▲
Chaque article sera fourni avec une preuve de faisabilité sous forme de code source et de démonstration.
Ces projets seront indépendants les uns des autres et développés en Visual Basic sous Visual Studio 2010. Ils seront uniquement des preuves de faisabilité et ne seront donc pas de qualité suffisante pour être utilisés tels quels en production.
Qualité insuffisante pour passer en production ! Pourquoi ?
Il ne s'agit pas ici de critère de qualité sur le code ; le code des preuves de faisabilité est fonctionnel et bien écrit (sauf erreur de ma part), mais ce code a été réalisé avec un seul objectif en tête : prouver que c'est possible... et utile.
- tests unitaires et / ou contrats de code ;
- architecture supportant l'évolution et la maintenance correctement (principe d'ouverture, fermeture, etc.) ;
- et plus globalement, tous les critères de qualité logicielle.
- Ces projets ne sont pas séparés en profil Client / Design, le code gérant le « Design Time » est directement intégré dans les projets. Ce qui nous force à modifier le profil des projets de « DotNet 4.0 Client Profile » à « DotNet 4.0 ». Normalement, en suivant ce qui se pratique en DotNet, le « Design Time » devrait être séparé du code fonctionnel et ainsi, devenir optionnel.
- Lorsque je réalise des preuves de faisabilité, toute question architecturale qui ne fait pas partie du sujet étudié est automatiquement éludée. Donc, il peut y avoir des raccourcis dangereux au niveau de la structure des objets.
- Pas de test unitaire, pas de contrat de code et juste des démonstrations minimalistes pour vérifier et démontrer le fonctionnement par l'exemple.
- Pour moi, un code se doit d'être lisible et accessible sans aucun commentaire. C'est pourquoi les preuves de faisabilité des articles ne contiendront aucun commentaire.
Finalité▲
Un projet regroupant toutes ces preuves de faisabilité en les améliorants pour les rendre utilisables en production sera fourni sur Developpez.Com.
Ce projet permettra l'utilisation de la liaison d'objets et proposera d'autres améliorations complémentaires à la liaison d'objets.
I. La liaison de données en Windows Forms▲
I-A. Constat▲
Comme tout développeur en Windows Forms, j'ai toujours été très déçu non pas du potentiel de la liaison de données, mais par sa sous-utilisation, un peu comme si Microsoft ne croyait pas trop en sa propre technologie.
Après plus de 10 ans d'expérience dans le développement d'application, j'ai pu constater que le code des interfaces graphiques est trop souvent du code de « plomberie » et encore plus souvent du code de liaison (telle méthode appelée sur tel évènement, etc.).
Que l'on utilise un patron de conception, sa propre méthode ou autre chose, on se rend vite compte que 60 % du code des interfaces graphiques est du code de liaison et rien d'autre. Et encore, j'abaisse volontairement mon estimation pour ne pas choquer les esprits sensibles.
Or justement, lorsque l'on se décide enfin à passer le cap et à utiliser la liaison de données pour remplacer tout ce code pas inutile mais sans aucune valeur ajoutée et sans aucune intelligence, on se rend tout de suite compte que... ce n'est pas possible !
En effet la liaison de données mérite son nom, elle est destinée à relier des données à des composants graphiques, et toutes ses lacunes et ses faiblesses viennent de cet objectif fonctionnel.
Pourtant le moteur de liaison utilisé par la liaison de données est beaucoup plus puissant que ne le laisse apparaître la liaison de données. Un exemple : le moteur de liaison gère très bien les propriétés imbriquées (nested properties), seules les interfaces graphiques pour saisir ces propriétés imbriquées ne les supportent pas.
I-B. Lacunes et faiblesses▲
Alors quelles sont ces lacunes et faiblesses de la liaison de données en Windows Forms ?
- seuls les contrôles supportent par défaut la liaison de données, les composants comme les ToolStrips ne les supportent pas ;
- l'éditeur de liaison n'est vraiment pas facile d'accès, si on conçoit ses interfaces graphiques centrées sur les liaisons, cela devient contre-productif. En plus, cet éditeur ne supporte pas les propriétés imbriquées ;
- pas de liaison sur les évènements ;
- pas de liaison sur les champs ;
- pas de liaison entre les propriétés et le résultat d'une méthode ou la valeur d'un champ ;
- pas de composant pour créer une vue sur un objet.
Dans cette série d'articles, je vais donc essayer de résoudre ces lacunes une par une et le tout sans réinventer la roue. J'entends par là que les résolutions se doivent le plus possible d'être compatibles avec l'existant.
En effet, à quoi bon faire tout ça, si l'on doit réécrire tous les contrôles des Windows Forms.
Absolument aucun intérêt, autant passer directement à WPF et / ou Silverlight.
II. Amélioration de l'ergonomie des liaisons▲
II-A. L'ergonomie existante▲
En Windows Forms on dispose de deux moyens pour saisir visuellement une liaison de données :
Public
Class
PersonPropertyModel
Private
_Address As
New
AddressPropertyModel
Public
Property
FirstName As
String
Public
Property
LastName As
String
Public
ReadOnly
Property
Address As
AddressPropertyModel
Get
Return
Me
._Address
End
Get
End
Property
End
Class
Public
Class
AddressPropertyModel
Public
Property
Address1 As
String
Public
Property
Address2 As
String
Public
Property
Address3 As
String
Public
Property
PostalCode As
Int32
Public
Property
City As
String
End
Class
- L'afficheur ne souffre d'aucun défaut et remplit très bien son rôle.
Il supporte parfaitement les propriétés imbriquées, et permet même de faire un glisser déplacer de ces propriétés pour créer directement le label et le contrôle de saisie associés. - L'éditeur, par contre, est difficile d'accès et souffre d'un bogue extrêmement gênant sur les propriétés imbriquées puisqu'il ne les supporte pas.
Pourtant les deux utilisent la même liaison de données.
On vient de mettre le doigt sur ce que j'appelle « lacunes et faiblesses » de la liaison de données.
C'est aussi ce genre de chose qui me fait penser que Microsoft, lors de la création des Windows Forms a expérimenté la liaison de données, mais n'a pas poussé le sujet jusqu'au bout, en tout cas, en Windows Forms.
II-B. Utilisation de l'éditeur de liaison▲
- Sélectionner un composant visuel ;
- Afficher la page de propriétés de ce composant visuel ;
- Sélectionner la propriété DataBindings ;
- Dérouler cette propriété ;
- Sélectionner la sous-propriété « Avancées » ;
- Cliquer sur le bouton qui ouvre l'éditeur.
- la propriété à lier ;
- la source de la liaison utilisée ;
- le mode de liaison de la source ;
- le format ;
- et la valeur nulle.
Et il faut répéter ces actions pour chaque liaison que l'on souhaite créer.
Pas très ergonomique tout ça.
II-C. La solution proposée▲
Sur la quantité d'informations à saisir pour configurer une liaison, on ne peut pas faire grand-chose. Hormis, peut-être, fournir un accès indépendant à chaque valeur pour faciliter l'accès à ces valeurs.
Par contre, concernant l'accès à l'éditeur de liaison, là, on peut faire beaucoup mieux. Je vous propose d'ajouter un onglet dans la PropertyGrid qui sera dédié aux liaisons sur les propriétés.
Ce qui donnera :
Comme on n'a pas réinventé la roue, mais ajouté un troisième moyen d'édition des liaisons, les modes d'édition standards sont toujours présents et fonctionnent toujours de la même façon.
Les nouveaux éditeurs supportent les propriétés imbriquées et les liaisons sur autre chose que des sources de données.
II-D. Réalisation de la solution proposée▲
Dans la preuve de faisabilité de cet article, il n'y a pas beaucoup de code intéressant.
Il y a beaucoup d'éditeurs visuels, qui sont de simples contrôles, beaucoup d'extensions pour faciliter l'écriture et la lecture du code et presque aucun code concernant les liaisons de données directement.
- comment ajouter un onglet à une PropertyGrid ;
- comment créer un éditeur utilisable dans une PropertyGrid.
Si vous n'êtes intéressé que par les liaisons, rendez-vous à l'étape suivante : .
II-D-1. Le principe de fonctionnement▲
L'onglet des liaisons peut être fourni par n'importe quel objet, cela n'a aucune importance.
II-D-2. Comment ajouter un onglet à une PropertyGrid ?▲
- Créer un onglet en héritant de PropertyTabPropertyTab ;
- Déclarer cet onglet sur un composant visuel via l'attribut PropertyTabAttributePropertyTabAttribute en précisant sa portée via l'énumération PropertyTabScopePropertyTabScope ;
- Utiliser le composant visuel de l'étape précédente dans le concepteur Windows Forms.
- fournir les informations sur l'onglet via les propriétés NomPropriété TabName et ImagePropriété Bitmap ;
- spécifier quand l'onglet peut être utilisé via la méthode CanExtendMéthode CanExtend ;
- fournir les descripteurs de propriétés via les méthodes GetDefaultPropertyMéthode GetDefaultProperty et GetPropertiesMéthodes GetProperties. Il s'agit de la partie la plus complexe.
L'attribut PropertyTabAttributeL'attribut PropertyTabAttribute ne peut pas être déclaré plusieurs fois sur un même objet. Par contre, on peut l'hériter et spécifier plusieurs onglets via cet héritage. Pour cela, l'héritier devra appeler la méthode InitializeArraysMéthode InitializeArrays de sa base.
On peut accéder aux onglets d'une PropertyGrid via la propriété PropertyTabsPropriété PropertyTabs.
II-D-3. Le code de l'onglet des liaisons▲
<
PermissionSetAttribute
(
SecurityAction.Demand
, Name:=
"FullTrust"
)>
Public
Class
BindingsPropertyTab
Inherits
PropertyTab
Private
_ServiceProvider As
IServiceProvider
Private
Sub
New
(
)
End
Sub
Public
Sub
New
(
ByVal
sp As
IServiceProvider)
MyBase
.New
(
)
If
sp Is
Nothing
Then
Throw
New
ArgumentNullException
(
"sp"
)
Me
._ServiceProvider
=
sp
End
Sub
Public
Overrides
ReadOnly
Property
Bitmap As
System.Drawing.Bitmap
Get
Return
My.Resources.BindingsTab
End
Get
End
Property
Public
Overrides
ReadOnly
Property
TabName As
String
Get
Return
My.Resources.BindingsTabName
End
Get
End
Property
Public
Overrides
ReadOnly
Property
HelpKeyword As
String
Get
Return
My.Resources.BindingsHelpKeyWord
End
Get
End
Property
Public
Overrides
Function
CanExtend
(
ByVal
extendee As
Object
) As
Boolean
Return
Me
.HasBindings
(
extendee)
End
Function
Public
Overrides
Function
GetDefaultProperty
(
ByVal
component As
Object
) As
PropertyDescriptor
Dim
Bindings =
Me
.GetBindings
(
component)
If
Bindings Is
Nothing
Then
Return
Nothing
Dim
DefaultBindingProperty =
BindingHelper.GetDefaultBindingProperty
(
component)
If
DefaultBindingProperty IsNot
Nothing
Then
Return
New
DesignableBindingPropertyDescriptor
(
component,
DefaultBindingProperty, Me
._ServiceProvider
, Bindings)
End
If
Dim
DefaultProperty =
TypeDescriptor.GetDefaultProperty
(
component)
If
DefaultProperty Is
Nothing
Then
Return
Nothing
Return
New
DesignableBindingPropertyDescriptor
(
component,
DefaultProperty, Me
._ServiceProvider
, Bindings)
End
Function
Public
Overloads
Overrides
Function
GetProperties
(
ByVal
component As
Object
,
ByVal
attributes
(
) As
Attribute) As
PropertyDescriptorCollection
Dim
ComponentBindings =
Me
.GetBindings
(
component)
Return
BindingHelper.GetBindingMembers
(
component,
ComponentBindings, attributes, Me
._ServiceProvider
)
End
Function
Public
Overrides
Function
GetProperties
(
ByVal
component As
Object
) As
PropertyDescriptorCollection
Dim
ComponentBindings =
Me
.GetBindings
(
component)
Return
BindingHelper.GetBindingMembers
(
component,
ComponentBindings, Nothing
, Me
._ServiceProvider
)
End
Function
Public
Overrides
Function
GetProperties
(
ByVal
context As
ITypeDescriptorContext,
ByVal
component As
Object
,
ByVal
attributes
(
) As
Attribute) As
PropertyDescriptorCollection
If
context.IsRootComponent
(
component) Then
Return
Me
.GetProperties
(
component, attributes)
Else
Return
TypeDescriptor.GetProperties
(
component, attributes)
End
If
End
Function
Protected
Overridable
Function
HasBindings
(
ByVal
component As
Object
) As
Boolean
If
component Is
Nothing
Then
Return
False
Return
TypeOf
component Is
IBindableComponent
End
Function
Protected
Overridable
Function
GetBindings
(
ByVal
component As
Object
) As
ControlBindingsCollection
If
component Is
Nothing
Then
Return
Nothing
If
Not
TypeOf
component Is
IBindableComponent Then
Return
Nothing
Return
DirectCast
(
component, IBindableComponent).DataBindings
End
Function
End
Class
Ce code est simple.
Les deux méthodes qui gèrent les liaisons sont HasBindings et GetBindings.
Ici, elles ne gèrent que les liaisons par défaut fournies par l'interface IBindableComponentInterface IBindableComponent.
II-D-4. Comment créer un éditeur visuel pour une propriété ?▲
Pour créer un éditeur visuel, il faut hériter de la classe UITypeEditorUITypeEditor.
- définir son comportement visuel via la méthode GetEditStyleMéthode GetEditStyle et la propriété IsDropDownResizablePropriété IsDropDownResizable si nécessaire ;
- écrire dans la méthode EditValueMéthode EditValue le code d'édition de la propriété ;
- déclarer son utilisation via l'attribut EditorAttributeEditorAttribute ou en modifiant la méthode GetEditorMéthode GetEditor d'un PropertyDescriptorClasse PropertyDescriptor.
-
via les attributs ;Sélectionnez
<
Editor
(
GetType
(
DesignableBindingDataMemberSelectorEditor),GetType
(
UITypeEditor))>
-
via la méthode GetEditor.Sélectionnez
Public
Overrides
Function
GetEditor
(
ByVal
editorBaseTypeAs
Type
)As
Object
Return
New
DesignableBindingEditorEnd
Function
II-D-5. Le code de l'éditeur utilisé pour les liaisons « éditables » ▲
Public
Class
DesignableBindingEditor
Inherits
UITypeEditor
Public
Overrides
Function
GetEditStyle
(
ByVal
context As
ITypeDescriptorContext) As
UITypeEditorEditStyle
Return
UITypeEditorEditStyle.Modal
End
Function
Public
Overrides
ReadOnly
Property
IsDropDownResizable As
Boolean
Get
Return
True
End
Get
End
Property
Public
Overrides
Function
EditValue
(
ByVal
context As
ITypeDescriptorContext,
ByVal
provider As
IServiceProvider, ByVal
value As
Object
) As
Object
If
provider Is
Nothing
Then
Return
value
If
value Is
Nothing
OrElse
Not
TypeOf
value Is
DesignableBinding Then
Return
value
Dim
UIService =
provider.GetService
(
Of
IWindowsFormsEditorService)(
)
If
UIService Is
Nothing
Then
Return
value
Dim
View =
Me
.CreateView
(
context, provider, DirectCast
(
value, DesignableBinding))
UIService.ShowDialog
(
View)
Return
View.BindingBox.Binding
End
Function
Private
Function
CreateView
(
ByVal
context As
ITypeDescriptorContext,
ByVal
provider As
IServiceProvider,
ByVal
binding As
DesignableBinding) As
BindingEditorDialog
Dim
View As
New
BindingEditorDialog
If
TypeOf
context.PropertyDescriptor
Is
DesignableBindingPropertyDescriptor Then
Dim
DBDescriptor =
DirectCast
(
context.PropertyDescriptor
, DesignableBindingPropertyDescriptor)
View.BindingBox.BindedComponent
=
DBDescriptor.Component
View.BindingBox.BindedMemberName
=
DBDescriptor.DisplayName
End
If
View.BindingBox.Binding
=
binding
View.BindingBox.ServiceProvider
=
provider
View.BindingBox.Fill
(
)
Return
View
End
Function
End
Class
- il récupère un service d'affichageService d'affichage ;
- il initialise le contrôle qui va permettre la saisie de la valeur (en fonction du contexte et de la valeur) ;
- il affiche ce contrôle via le service d'affichage ;
- il retourne la valeur, modifiée ou non.
II-D-6. L'architecture de services du concepteur Windows Forms▲
Toute la difficulté de l'utilisation des onglets de propriétés et des éditeurs visuels réside non pas dans les classes elles-mêmes, mais dans l'architecture de services du concepteur Windows FormsArchitecture de design.
Mieux on connaît cette architecture, plus facile est la gestion du « Design Time ».
II-D-6-1. Le fournisseur de services▲
La première chose à savoir, c'est que tous les services sont fournis par un objet du type IServiceProviderInterface IServiceProvider.
Dans le cas d'un UITypeEditorClasse UITypeEditor, ce fournisseur de services est passé en paramètre de la méthode EditValueMéthode EditValue.
On peut récupérer à tout instant ce fournisseur de services par d'autres moyens, notamment par le biais du SitePropriété Site attaché à chaque composant puisque l'interface ISiteInterface ISite hérite de l'interface IServiceProviderInterface IServiceProvider.
Un petit conseil ; lorsque vous utilisez ces services, n'hésitez pas à utiliser des extensions pour faciliter leur usage, sinon, une simple ligne, un simple appel peuvent vite devenir un enfer.
Namespace
Extensions
<
Extension
(
)>
_
Public
Module
ServiceExtensions
#Region
"IServiceProvider"
<
Extension
(
)>
Public
Function
GetService
(
Of
TService As
Class
)(
ByVal
SP As
IServiceProvider) As
TService
If
SP Is
Nothing
Then
Return
Nothing
Return
TryCast
(
SP.GetService
(
GetType
(
TService)), TService)
End
Function
#End
Region
End
Module
End
Namespace
II-D-6-2. Les principaux services▲
- IComponentChangeService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.icomponentchangeservice.aspx
- IDesignerHost : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.idesignerhost.aspx
- IExtenderListService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.iextenderlistservice.aspx
- IExtenderProviderService: http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.iextenderproviderservice.aspx
- IReferenceService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.ireferenceservice.aspx
- ISelectionService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.iselectionservice.aspx
- ITypeDiscoveryService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.itypediscoveryservice%28v=VS.100%29.aspx
- ITypeResolutionService : http://msdn.microsoft.com/fr-fr/library/system.componentmodel.design.ityperesolutionservice.aspx
- IPropertyValueUIService : http://msdn.microsoft.com/fr-fr/library/system.drawing.design.ipropertyvalueuiservice.aspx
- IUIService : http://msdn.microsoft.com/fr-fr/library/system.windows.forms.design.iuiservice%28v=VS.100%29.aspx
- IWindowsFormsEditorService : http://msdn.microsoft.com/fr-fr/library/system.windows.forms.design.iwindowsformseditorservice.aspx
Et ce ne sont que les plus utilisés.
La plupart du temps, ils se trouvent dans les espaces de nom qui se terminent par Design.
Je vous laisse consulter les liens MSDN si le sujet vous intéresse.
III. Démonstration▲
Pour démontrer l'utilité de la solution proposée dans cet article, nous allons utiliser un modèle de données des plus classiques qui soient et le lier à une représentation visuelle.
En plus de tout ça, nous allons ajouter un contrôle qui va se lier à un autre contrôle (sans passer par une source de donnéesComposant BindingSource).
III-A. Les modèles de données ▲
<
PropertyTab
(
GetType
(
BetterAccessibility.BindingsPropertyTab
), PropertyTabScope.Document
)>
Public
Class
PersonModel
Inherits
Component
Private
_Address As
New
AddressModel
<
DisplayName
(
"Prénom"
)>
Public
Property
FirstName As
String
<
DisplayName
(
"Nom"
)>
Public
Property
LastName As
String
<
DisplayName
(
"Adresse"
)>
<
DesignerSerializationVisibility
(
DesignerSerializationVisibility.Content
)>
Public
ReadOnly
Property
Address As
AddressModel
Get
Return
Me
._Address
End
Get
End
Property
End
Class
<
TypeConverter
(
GetType
(
ExpandableObjectConverter))>
Public
Class
AddressModel
<
DisplayName
(
"Adresse"
)>
Public
Property
Address As
String
<
DisplayName
(
"Complément d'adresse"
)>
Public
Property
Complement As
String
<
DisplayName
(
"Code postal"
)>
Public
Property
PostalCode As
Int32
<
DisplayName
(
"Ville"
)>
Public
Property
City As
String
End
Class
Ce modèle est une adaptation du premier modèle utilisé dans cet article.
Le modèle racine est un composant afin de pouvoir l'inclure dans la vue.
Il active aussi l'onglet de liaison. N'importe quel autre objet aurait pu remplir ce rôle.
III-B. Le formulaire de démonstration▲
Public
Sub
New
(
)
' Cet appel est requis par le concepteur.
InitializeComponent
(
)
' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
Me
.PersonModelBindingSource.DataSource
=
Me
.PersonModel1
End
Sub
Le code utilisateur complet du formulaire se résume au code du constructeur ci-dessus.
Tout le code des liaisons se situe dans le code généré par Visual Studio.
Les différentes liaisons fonctionnent parfaitement.
Lorsque l'on modifie le nom, son clone est automatique modifié.
La liaison du clone fonctionne sans passer par une source de données.
III-C. Conclusion▲
La démonstration de cet article est loin d'être parfaite, elle peut être améliorée de diverses manières.
- exposer le IFormatProviderInterface IFormatProvider utilisé par les liaisons et permettre de le configurer ;
- ajouter le support des sélections multiples de propriétés afin de pouvoir modifier plusieurs liaisons en même temps ;
- améliorer les éditeurs visuels (images, meilleurs groupements... ) ;
- ajouter le support des liaisons fournies par extensions (voir l'article suivant de la série : « des liaisons sur les composantsWindows Forms - de la liaison de données à la liaison d'objets - partie 2 : des liaisons sur les composants ») ;
- gérer les propriétés imbriquées dans l'onglet des liaisons.
Néanmoins, la preuve est faite, il est possible d'améliorer l'ergonomie des liaisons, et ce, sans toucher aux liaisons en question.
D'ailleurs, en ce faisant, nous avons pu observer et corriger une autre lacune / manque des éditeurs standards : ceux-ci ne permettent pas d'éditer des liaisons en dehors de celles proposées pas les sources de données, or, le moteur de liaison le supporte parfaitement.
Ceci conclut cet article, mais pas cette série ; prochaine lacune : « des liaisons sur les composantsWindows Forms - de la liaison de données à la liaison d'objets - partie 2 : des liaisons sur les composants ». On pourra y observer la magie de certains patrons de conception.
Je n'en dis pas plus, vous pourrez le constater par vous-même.
Merci à vous et à bientôt.
Remerciements▲
J'adresse ici tous mes remerciements à tous les membres de l'équipe de rédaction de "developpez.com" pour le temps qu'ils ont bien voulu passer à la correction et à l'amélioration de cet article.
Merci à Jacques JeanProfil de Jacques Jean pour ses corrections et sa relecture attentive ainsi qu'à Philippe VialatteProfil de Philippe Vialatte pour son accueil dans l'équipe et ses conseils.
Contact et code source▲
Si vous constatez une erreur dans l'article, dans les sources ou pour toute autre information, n'hésitez pas à me contacter via le forum de l'articleForum de l'article.
Le code source de la preuve de faisabilité est disponible iciLes sources de la preuve de faisabilité.