IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Architecture en "couches"


Sujet :

VB.NET

  1. #1
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut Architecture en "couches"
    Bonjour à tous,
    J'ai appris beaucoup sur vb.net en quelques années en faisant maintenant usage de répertoires (pour classer mon code) associés à des Namespace et j'aimerais progresser encore un peu.
    (Donc si j'ai bien compris les Namespace peuvent plus ou moins symboliser les couches en gros)

    Pour rentrer dans le vif du sujet et en simplifiant à l’extrême, mon programme est constitué comme ceci :
    - Des Forms (dans la couche UI donc)...
    - Des classes et des objets qui représente plus ou moins ma couche BLL
    - Une classe pour gérer plusieurs Backgroundworker pour charger les données et qui est plus ou moins ma couche d’accès aux données (ma BDD on va dire...)

    Donc logiquement je fait communiquer les couches comme ceci : BDD<->BLL<->UI
    Hors je m'appercois que BDD à besoin de communiquer avec UI (pour que mon bgw affiche la progression).
    QUESTION : Est ce que je dois passer par BLL pour faire communiquer BDD et UI indirectement ? Alors que cela complique le code avec des doublons de procédures que je pourrais éviter. Sans compter le risque d'utiliser des class qui pourrait ne pas être instancié quand j'en ai besoin....Bref...

    Je ne sais pas comment faire mes choix en fait. Je suis Ok pour éclater mon code en pleins de class et faire communiquer X class mais si je décide faire 3 niveaux de couches, est ce que je suis contraint de passer par la couche 2 pour faire communiquer 1 et 3 comme pour l'exemple cités ci-dessus.

    J'arrive à faire de bons programme mais en architecture je vraiment pas doué et comme je pense que beaucoup d'entre vous sont des codeurs pro avec de l’expérience ça m'aiderait vraiment beaucoup. Merci beaucoup pour le petit coup de pouce....

  2. #2
    Modérateur
    Avatar de DotNetMatt
    Homme Profil pro
    CTO
    Inscrit en
    Février 2010
    Messages
    3 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : CTO
    Secteur : Finance

    Informations forums :
    Inscription : Février 2010
    Messages : 3 611
    Points : 9 743
    Points
    9 743
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par BasicZX81 Voir le message
    Donc logiquement je fait communiquer les couches comme ceci : BDD<->BLL<->UI
    Hors je m'appercois que BDD à besoin de communiquer avec UI (pour que mon bgw affiche la progression).
    QUESTION : Est ce que je dois passer par BLL pour faire communiquer BDD et UI indirectement ?
    Tu as donne la reponse toi-meme. L'UI ne doit JAMAIS contacter directement ta couche BDD.

    Citation Envoyé par BasicZX81 Voir le message
    Alors que cela complique le code avec des doublons de procédures que je pourrais éviter. Sans compter le risque d'utiliser des class qui pourrait ne pas être instancié quand j'en ai besoin....Bref...
    Si tu dois creer des doublons alors tu as probablement un souci de conception. Il faut probablement que tu refactorises ton code pour isoler les parties dont tu as besoin plusieurs fois.

    Citation Envoyé par BasicZX81 Voir le message
    Je suis Ok pour éclater mon code en pleins de class et faire communiquer X class mais si je décide faire 3 niveaux de couches, est ce que je suis contraint de passer par la couche 2 pour faire communiquer 1 et 3 comme pour l'exemple cités ci-dessus.
    Oui, tu dois absolument respecter ton architecture. Sinon, il n'y a aucun interet a decouper le code en plusieurs couches

    Quand tu dis "BDD", tu parles de la couche d'acces aux donnees (DAL) ou bien de la base de donnees elle-meme ?
    Less Is More
    Pensez à utiliser les boutons , et les balises code
    Desole pour l'absence d'accents, clavier US oblige
    Celui qui pense qu'un professionnel coute cher n'a aucune idee de ce que peut lui couter un incompetent.

  3. #3
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir,

    Je rejoins DotNetMatt sur le souci de conception.

    Je souhaite également enfoncer le clou sur un point tout particulièrement :

    L'architecture 3tiers (Modèle - Vue - Controlleur) requiert de solides notions en POO car la communication entre couches demande une certaine maîtrise des percepts suivants :

    - identification des messages véhiculant au sein de ton projet : création d'évènements (+ abonnement/désabonnement)
    - Interface (Imlements : qui rends service à qui ?)
    - héritage : le plus simple de tous finalement

    La factorisation est un moyen d'atteindre un bon niveau de granularité afin de ne conserver que l'essentiel du projet.

    Tu peux être quelqu'un de très organisé mais saches qu'il est assez difficile d'adapter un projet à ce type de pattern.
    A noter qu'il est assez rare d utiliser ce type de pattern pour du Windows form... ceux qui le font le pratiquent generalement au quotidien dans des projets Web.

    Bon courage.

  4. #4
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Merci pour vos réponses, d'autant que c'est la première fois qu'on me réponds sur ces principes d'architectures .
    @DotNetMatt : en réalité je n'ai pas de base de données, c'est plus une couche d’accès aux données je pense. Puisque pour des raisons pratique j'ai choisie de stocker mes données dans du XML personnalisé.

    @Wallace1 : Des notions de POO j'en ai quelques unes mais j'avoue qu'elles ne sont pas très solide .
    Ça viens petit à petit mais c'est extrêmement difficile dans mon cas car comme je l'ai peut-être déjà dit j'ai toujours appris tous seul.

    Bon ,alors en fait j'ai commencé à "éclater" mon code en une multitude de classe de modules, de Namespace....etc (enfin c'est plutôt une copie de code car je ne touche pas aux code qui fonctionne déjà au cas ou). Cette méthode tant à rendre le code de plus en plus claire et organisé mais c'est une grosse galère et déjà j'ai un problème que je n'arrive pas à régler :

    J'ai mis en place tout un système de Notification pour signaler ma BLL les changements issues de mes collections d'objets ou des objets eux-mêmes.
    Problème : Le code Passe sur le RaiseEvent de la Class Cars, par contre le Handler d’événement n'ai pas levé dans BLLCars alors que celle-çi est initialisé puisque le New et le InitializeComponent sont déjà exécuté.

    PS : J'ai fait du Shared dans la 2eme classe, ce n'ai rien d'autres qu'un portage de mes anciennes procédures qui était dans ma Form car j'ai une meilleur lisibilité pour l'instant. Ma 1ére étape c'est déjà de séparer les fonctions, après j'y verrais plus claire .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     Public Class Cars
            Inherits SortedDictionary(Of String, Car)
            Public Event CarAdded(Sender As Object, ByVal e As CarsEventArgs)
            Public Sub New()
                MyBase.New(StringComparer.CurrentCultureIgnoreCase)
                AddHandler GlobalNotifierCar.PropertyChanged, AddressOf PropertyCarChanged
            End Sub
            Public Overloads Sub Add(CarName As String, Car As Car)
                Car.Parent = Me
                MyBase.Add(CarName, Car)
                RaiseEvent CarAdded(Me, New CarsEventArgs(CarName))
            End Sub
     End Class
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     Public Class BLLCars
            Shared Sub New()
                InitializeComponent()
            End Sub
            Private Shared Sub InitializeComponent()
                AddHandler Cars1.CarAdded, AddressOf CarAdded
            End Sub
            Private Shared Sub CarAdded(Sender As Object, e As CarsEventArgs)
     
            End Sub
     
     End Class
    Si vous avez une idée, je suis ouvert à tout (pas de problème...)

  5. #5
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir,

    Pourquoi ne pas utiliser une ObservableCollection qui a l'avantage de savoir quand est-ce que la collection d'items change (Add, Update, Remove) ?

    EDIT : arf j'avais mal regardé tu essayes de faire la même chose avec un SortedDictionary....

    De plus on ne gère pas les événements via des classes Shared au risque de perdre la référence de l'instance (il y a des exceptions mais ca devient difficilement maintenable sur le long terme) ..... au passage je ne vois pas la référence à la classe "Cars1" dans ta classe Shared "BLLCars" ????
    Ton délégué se situe ou pour ton EventArgs (CarsEventArgs) ?

  6. #6
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonjour,
    Oui pour le SortedDictionnary, en réalité j'utilise au maximum les objets courants du framework. Je fait des collections personnalisées ou autres que si vraiment j'ai pas le choix.
    J'ai référencé Cars1 dans un module puisque je considére que c'est un des objets principaux du programme qui doit rester accessible de partout (et je n'ai besoin que d'une seule instance en réalité) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Module Main
    Public Cars1 As New Cars
    End Module
    Alors j'avais pas mis tout le code pour ne pas surcharger, voici le reste :

    Le GlobalNotifierCar est une invention à moi : C'est un objet que je reference dans la class Car, je peux accéder ainsi à tous les changements de propriété de tous les objets Car partout ou j'en ai besoin mais je sais pas encore si c'est une bonne idée (je test). Je précise de plus que je n'ai pas testé beaucoup ce nouveau code....il se peux que cela ne fonctionne pas ou mal.
    (Au passage j'ai rajouté une ligne que j'avais oublié dans mon 1er post dans le New de Cars).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      Public Class GlobalNotifierCar
            Public Shared Event PropertyChanged As PropertyChangedEventHandler
            'Private Sub New()
     
            'End Sub
            Public Shared Sub NotifyPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
                RaiseEvent PropertyChanged(sender, e)
            End Sub
        End Class
    "NotifyPropertyChanged" est une méthode de la classe de base "BaseContent" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
        Public Class Car
            Inherits BaseContent
            'Public Event CarChanged(Sender As Object, ByVal e As CarsEventArgs)
            Private _Catégorie As String
            Private _Marque As String
            Private _CarsParent As Cars
            <XmlIgnore>
            Public Property Parent() As Cars
            <XmlIgnore>
            Public Shared Property GlobalCarNotifier() As GlobalNotifierCar
            'Private Sub New()
            '    MyBase.New()
            'End Sub
            Public Sub New(CarName As String)
                MyBase.New(CarName)
                InitializeComponent()
            End Sub
            Public Sub New(CarName As String, Original As Boolean) 
                MyBase.New(CarName, Original)
                InitializeComponent()
            End Sub
            Private Sub InitializeComponent()
                AddHandler MyBase.PropertyChanged, AddressOf PropertyChanged
            End Sub
            Private Shadows Sub PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
                GlobalNotifierCar.NotifyPropertyChanged(sender, e)
            End Sub
            Public Property Catégorie() As String
                Get
                    Return _Catégorie
                End Get
                Set(ByVal value As String)
                    _Catégorie = value
                    NotifyPropertyChanged()
                End Set
            End Property
            Public Property Marque() As String
                Get
                    Return _Marque
                End Get
                Set(ByVal value As String)
                    _Marque = value
                    NotifyPropertyChanged()
                End Set
            End Property
            ....etc
    End Class
    Car hérite de BaseContent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
       Public Class BaseContent
            Implements INotifyPropertyChanged
            Private _Name As String
            Private _NewContent As Boolean
            Private _Original As Boolean
            Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
            Protected Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
            End Sub
            Public Sub New()
                ' New sans argument necessaire pour serializer les classes dérivées
            End Sub
            Public Sub New(Name As String)
                _Name = Name
            End Sub
            Public Sub New(Name As String, Original As Boolean)
                _Name = Name
                _Original = Original
                SetLocked()
            End Sub
            Public Property Name() As String
                Get
                    Return _Name
                End Get
                Set(ByVal value As String)
                    _Name = value
                    NotifyPropertyChanged()
                End Set
            End Property
     
            Public Property NewContent() As Boolean
                Get
                    Return _NewContent
                End Get
                Set(ByVal value As Boolean)
                    _NewContent = value
                    NotifyPropertyChanged()
                End Set
            End Property
            '<XmlIgnore>
            Public Property Original() As Boolean
                Get
                    Return _Original
                End Get
                Set(ByVal value As Boolean)
                    _Original = value
                    NotifyPropertyChanged()
                End Set
            End Property
            ....etc
    End Class
    De plus on ne gère pas les événements via des classes Shared au risque de perdre la référence de l'instance
    Est ce que c'est pour ça que je n'arrive pas à lever l’événement Added dans BLLCars ?
    Pour les shared dans BLLCars, j'ai fait comme ça car je me suis dit que je n'utiliserais qu'une seule instance de BLLCars, et que cela ma facilite la compréhension (pour l'instant) car je suis obligé de rappeler BBLCars partout dans mon code. Ainsi, je suis sûre que les méthodes de BLLCars que j'utilise appartient bien à BLLCars.
    Il faut juste le voir comme une astuce de débutant (peut-être provisoire) mais c'est peut-être pas ce qu'il faudrait faire à terme, il vaut mieux que je fasse un objet instanciable unique ?

    D'ailleurs je me pose une question à propos de "Shared New" de BLLCars car à aucun moment je fait un New BLLCars dans mon code et je me demande à quel moment le New est effectué. Je pense qu'il s’exécute dés l'instant ou on fait référence à BLLCars ce qui peux être extrêmement problématique car on ne sait jamais quand et si la classe est initialisé (ou instancié, je sais pas comment on dit dans ce cas). Est ce que c'est bien ça ?

  7. #7
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par BasicZX81 Voir le message
    D'ailleurs je me pose une question à propos de "Shared New" de BLLCars car à aucun moment je fait un New BLLCars dans mon code et je me demande à quel moment le New est effectué. Je pense qu'il s’exécute dés l'instant ou on fait référence à BLLCars ce qui peux être extrêmement problématique car on ne sait jamais quand et si la classe est initialisé (ou instancié, je sais pas comment on dit dans ce cas). Est ce que c'est bien ça ?
    Le constructeur est appelé lors de l’initialisation de ta classe "BLLCars" donc comprends que le constructeur Shared n'est appelé qu'une seule fois jusqu'à la fermeture de ton programme. En fait l'instanciation se fait dès le 1er appel à une méthode de ta classe shared ensuite il n'a plus lieu.

    Il y a bien évidement différentes approches pour la conception d'un projet de type "gestion de véhicules" mais de ce que je peux voir cela me semble cohérent

    J'aurais des propositions d'évolutions à te faire part mais je suis actuellement sur un gros projet et je n'ai plus qu'une semaine pour le clôturer...... 1 an et demi de chantier..... pour déboucher sur une licence GPLv2....

    ++

  8. #8
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonjour Wallace1, ca serait vraiment sympa si je pouvais bénéficier de tes propositions d'évolutions. Je peux mettre en stand-by cette partie du code pour faire évoluer d'autres parties...je préfère avancer doucement mais surement et j'ai déjà des éléments pour réfléchir de mon coté.
    Je comprends le temps que ça prends de travailler sur de gros projet. Je sais pas ce que c'est une licence GPLv2 mais bon courage...

  9. #9
    Membre averti
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2012
    Messages
    640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mars 2012
    Messages : 640
    Points : 372
    Points
    372
    Par défaut
    Bonjour à tous, Désolé de faire mon "boulet" mais j'aimerais vraiment comprendre ce qui se passe car j'ai un événement qui est appelé 2 fois au lieu d'1 :

    Comme vous pouvez le voir j'ai supprimé la classe "GlobalNotifierCar" car j'estime qu'elle n'apporte pas grand chose.
    - L'Event "PropertyChanged de Car est un événement partagé pour être avertie de tous les changements de toutes les instances de Car.
    - La collection "Cars" est abonnée à cette Event. Le but est que cette classe puisse à son tour informer la BLL de tous les changements de Propriété de tous les objets Car qui font partie de la collection.

    A priori sur le papier tous me semble correct, sauf que pour un seul Event de l'objet Car, j'obtiens 2 events dans Cars (j'ai mis un point d’arrêt sur Debug.Writeline pour vérifier).
    La seule différence que j'ai noté est que sur le 1er Event la collection est vide, sur le 2eme j'ai plus de 200 Objets dans la collection.
    Mon réflexe à été de vérifier combien d'instance de Cars j'avais dans mon programme, apriori un seul donc je ne comprends pas pourquoi ce double appel.

    C'est un morceau de code que je vais généraliser donc j'aimerais le faire bien et propre, merci beaucoup si vous pouvez m'aider car je suis perdu sur ce coup...
    Je souhaiterais comprendre en 1er lieu et éventuellement avoir des propositions.

    Le code de test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            Dim Car As New Car("_Car1")
            Cars1.Add("_Car1", Car)
            'Cars1("_Car1").Marque = "Mercedes"
            Car.Marque = "Mercedes"
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     Public Class Cars
            Inherits SortedDictionary(Of String, Car)
            Public Event CarAdded(Sender As Object, ByVal e As CarsEventArgs)
            Public Event PropertyChanged As PropertyChangedEventHandler
            Public Sub New()
                MyBase.New(StringComparer.CurrentCultureIgnoreCase)
                AddHandler Car.PropertyChanged, AddressOf PropertyCarChanged
            End Sub
            Public Overloads Sub Add(CarName As String, Car As Car)
           If Not MyBase.ContainsKey(CarName) Then
                    Car.Parent = Me
                    MyBase.Add(CarName, Car)
                    RaiseEvent CarAdded(Me, New CarsEventArgs(CarName))
                End If
            End Sub
          Private Sub PropertyCarChanged(sender As Object, e As PropertyChangedEventArgs)
                Dim Car As Car = CType(sender, Car)
                Debug.WriteLine(String.Format("Cars/CarPropertyChanged : {0}", Car.Name))
                If Car.Parent Is Me Then RaiseEvent PropertyChanged(sender, e)
            End Sub
     End Class
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     Public Class Car
            Inherits BaseContent
            Private _Catégorie As String
            Private _Marque As String
            Private _CarsParent As Cars
            <XmlIgnore>
            Public Property Parent() As Cars
            Public Shared Shadows Event PropertyChanged As PropertyChangedEventHandler
     
            Public Sub New(CarName As String)
                MyBase.New(CarName)
                InitializeComponent()
            End Sub
            Public Sub New(CarName As String, Original As Boolean) 
                MyBase.New(CarName, Original)
                InitializeComponent()
            End Sub
            Private Sub InitializeComponent()
                AddHandler MyBase.PropertyChanged, AddressOf PropertyChanged
            End Sub
            Private Shadows Sub PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
                RaiseEvent PropertyChanged(sender, e)
            End Sub
            Public Property Catégorie() As String
                Get
                    Return _Catégorie
                End Get
                Set(ByVal value As String)
                    _Catégorie = value
                    NotifyPropertyChanged()
                End Set
            End Property
            Public Property Marque() As String
                Get
                    Return _Marque
                End Get
                Set(ByVal value As String)
                    _Marque = value
                    NotifyPropertyChanged()
                End Set
            End Property
            ....etc
    End Class

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo