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

Windows Presentation Foundation Discussion :

DataContext, View-ViewModel & DependencyProperties - Quelle méthodologie adopter ? [Débutant]


Sujet :

Windows Presentation Foundation

  1. #1
    Membre actif Avatar de AcidLines
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2010
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Février 2010
    Messages : 198
    Points : 279
    Points
    279
    Par défaut DataContext, View-ViewModel & DependencyProperties - Quelle méthodologie adopter ?
    Bonjour,

    Je suis débutant en WPF avec le Design Pattern MVVM et je souhaite respecter au maximum celui-ci.
    J'ai commencé pour mon application, à créer un petit UserControl qui va gère les action Agrandir/Réduire/fermer des fenêtres (afin de personnaliser leur design)

    Mon UserControl a des DependencyProperty permettant d'afficher ou non chaque bouton.

    View.MyUserControl.WinControls
    Code XAML : 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
     
     <StackPanel Orientation="Horizontal">
            <Button x:Name="MinBoxUI"  Command="{Binding MinimizeWindowCommand}" Style="{StaticResource WinControlStyle}" Content="{DynamicResource window-minimize}" Visibility="{Binding Path=MinimizeBox}"/>
            <Button x:Name="MaxBoxUI" Command="{Binding MaximizeWindowCommand}" Visibility="{Binding Path=MaximizeBox}">
                <Button.Style>
                    <!-- On surcharge le style WinControlStyle (Héritage BasedOn)-->
                    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource WinControlStyle}">
                        <Setter Property="Content" Value="{DynamicResource window-maximize}"></Setter>
                        <Style.Triggers>
                            <!-- Changement du glyph du bouton en fonction de l'état actuel de la fenêtre-->
                            <DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType=Window}}" Value="Maximized">
                                <Setter Property="Content" Value="{DynamicResource window-restaure}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
            <Button x:Name="CloseBoxUI" Command="{Binding CloseWindowCommand}"  Style="{StaticResource WinControlStyle}" Content="{DynamicResource window-close}" Visibility="{Binding Path=CloseBox}"/>
        </StackPanel>

    Le code Behind de la View sert uniquement à créer les DependancyProperties de mon UserControl.

    View.MyUserControl
    Code VB : 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
    52
    53
    54
    55
     
    Imports System.ComponentModel
     
     
    Namespace View.MyUserControl
        Partial Public Class WinControls
            Inherits Controls.UserControl
     
     
            Public Shared ReadOnly MaximizeBoxProperty As DependencyProperty = DependencyProperty.Register("MaximizeBox", GetType(Windows.Visibility), GetType(WinControls), Nothing)
            Public Shared ReadOnly MinimizeBoxProperty As DependencyProperty = DependencyProperty.Register("MinimizeBox", GetType(Windows.Visibility), GetType(WinControls), Nothing)
            Public Shared ReadOnly CloseBoxProperty As DependencyProperty = DependencyProperty.Register("CloseBox", GetType(Windows.Visibility), GetType(WinControls), Nothing)
     
     
            <Description("Vibilité du bouton réduire"), Category("Visibility")>
            Public Property MaximizeBox As Windows.Visibility
                Get
                    Return CType(GetValue(MaximizeBoxProperty), Windows.Visibility)
                End Get
                Set(value As Windows.Visibility)
                    SetValue(MaximizeBoxProperty, value)
                End Set
            End Property
            <Description("Vibilité du bouton agrandir"), Category("Visibility")>
            Public Property MinimizeBox As Windows.Visibility
                Get
                    Return CType(GetValue(MinimizeBoxProperty), Windows.Visibility)
                End Get
                Set(value As Windows.Visibility)
                    SetValue(MinimizeBoxProperty, value)
                End Set
            End Property
            <Description("Visibilité du bouton fermer"), Category("Visibility")>
            Public Property CloseBox As Windows.Visibility
                Get
                    Return CType(GetValue(CloseBoxProperty), Windows.Visibility)
                End Get
                Set(value As Windows.Visibility)
                    SetValue(CloseBoxProperty, value)
                End Set
            End Property
     
     
            Sub New()
                ' Cet appel est requis par le concepteur.
                InitializeComponent()
     
     
                ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
                Me.DataContext = Me
     
     
            End Sub
        End Class
    End Namespace

    De cette manière ci, les propriétés de mon UserControl (CloseBox, MaximizeBox, MiniMizeBox) sont bien répercutés quand j'utilise mon UserControl. Cependant mes Commandes qui sont dans un fichier ViewModel ne fontionne pas, ce qui est normal car le contexte défini par mon contrôle est "lui-même".

    Du coup si je change le DataContext pour mon ViewModel, les commandes fonctionnent mais pas les propriétés de dépendances.

    ViewModel.WinControlViewModel
    Code VB : 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
    52
    53
    54
    55
    56
    57
    58
    59
     
    Imports System.ComponentModel
    Imports System.Runtime.CompilerServices
     
     
    Namespace ViewModel
        Public Class WinControlsViewModel
     
     
    #Region "####### GESTIONNAIRE DE COMMANDES ###################"
     
     
            Private _CloseWindowCommand As Commands.RelayCommand(Of Application) = New Commands.RelayCommand(Of Application)(AddressOf Me.CloseWindow)
            Private _MinimizeWindowCommand As Commands.RelayCommand(Of Window) = New Commands.RelayCommand(Of Window)(AddressOf Me.MinimizeWindow)
            Private _MaximizeWindowCommand As Commands.RelayCommand(Of Window) = New Commands.RelayCommand(Of Window)(AddressOf Me.MaximizeWindow)
     
     
            Public ReadOnly Property CloseWindowCommand As Commands.RelayCommand(Of Application)
                Get
                    Return _CloseWindowCommand
                End Get
            End Property
     
     
            Public ReadOnly Property MinimizeWindowCommand As Commands.RelayCommand(Of Window)
                Get
                    Return _MinimizeWindowCommand
                End Get
            End Property
     
     
            Public ReadOnly Property MaximizeWindowCommand As Commands.RelayCommand(Of Window)
                Get
                    Return _MaximizeWindowCommand
                End Get
            End Property
     
     
            Private Sub CloseWindow(ByVal App As Application)
                Application.Current.Shutdown()
            End Sub
            Private Sub MinimizeWindow()
                Application.Current.MainWindow.WindowState = WindowState.Minimized
            End Sub
            Private Sub MaximizeWindow()
                Select Case Application.Current.MainWindow.WindowState
                    Case WindowState.Normal
                        Application.Current.MainWindow.WindowState = WindowState.Maximized
                    Case WindowState.Maximized
                        Application.Current.MainWindow.WindowState = WindowState.Normal
                End Select
     
     
            End Sub
    #End Region
     
     
        End Class
    End Namespace

    Dans le code Behind de la vue, j'ai tenté de mettre une Public Property référençant mon ViewModel de cette manière :

    View.MyUserControl
    Code VB : 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
     
     Private _VMDataContext As ViewModel.WinControlsViewModel
     
     
            Public ReadOnly Property VMDataContext As ViewModel.WinControlsViewModel
                Get
                    Return _VMDataContext
                End Get
            End Property
     
     
     
     
            Sub New()
                ' Cet appel est requis par le concepteur.
                InitializeComponent()
     
     
                _VMDataContext = New ViewModel.WinControlsViewModel
     
     
                ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
                Me.DataContext = Me
            End Sub

    et du coup je Bind mes commandes comme ceci :
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <Button x:Name="CloseBoxUI" Command="{Binding VMDataContext.CloseWindowCommand}"  Style="{StaticResource WinControlStyle}" Content="{DynamicResource window-close}" Visibility="{Binding Path=CloseBox}"/>

    Du coup tout fonctionne mais ma grande question est: Est ce que c'est la meilleur méthode ?
    J'ai cru comprendre qu'il fallait garder la création des DependencyProperty dans le Code-Behind de la View mais que les différents traitements devaient être réalisés dans le ViewModel.

    Du coup comment garder l'esprit MVVM en gérant le Contexte de la vue pour les DependencyProperty et les traitements de du ViewModel ?
    Je n'arrive pas à trouver de réponse concrète sur ces interactions.

    Merci d'avance si vous avez de quoi m'aiguiller
    Bonne journée à vous !

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    Citation Envoyé par AcidLines Voir le message
    je souhaite respecter au maximum celui-ci
    y a plusieurs interprétation possible, donc cherche les défauts quand même pour savoir quand ne pas tout respecter



    sinon

    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    <StackPanel Orientation="Horizontal" x:Name="mainControl">

    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mainControl.DataContext = Me
    comme ca tout fonctionnera
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre actif Avatar de AcidLines
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2010
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Février 2010
    Messages : 198
    Points : 279
    Points
    279
    Par défaut
    Bonjour,

    Merci pour ta réponse.

    Le fait de mettre le datacontext dans le stackpanel plutôt que sur le UserControl entier ne change rien pour moi.
    Les dependency properties sont prises en compte si je met le Datacontext sur lui même mais pas les commandes (contenues dans mon ViewModel)

    Seul le fait de déclarer une Propriété faisant référence à mon view Model dans le code behind de la view du User Control et en bindant ma commande de cette manière fais que cela fonctionne.

    Mais est ce bien la meileure solution ?

    Code behind de la view du UserControl
    Code VB : 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
     
            Private _VMDataContext As ViewModel.WinControlsViewModel
     
     
            Public ReadOnly Property VMDataContext As ViewModel.WinControlsViewModel
                Get
                    Return _VMDataContext
                End Get
            End Property
     
     
     
     
            Sub New()
                ' Cet appel est requis par le concepteur.
                InitializeComponent()
     
     
                _VMDataContext = New ViewModel.WinControlsViewModel
     
     
                ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
                Me.DataContext = Me
     
     
            End Sub
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <Button x:Name="CloseBoxUI" Command="{Binding VMDataContext.CloseWindowCommand}"  Style="{StaticResource WinControlStyle}" Content="{DynamicResource window-close}" Visibility="{Binding Path=CloseBox}"/>

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    j'avais mal lu
    et normalement quand on fait me.datacontext = me c'est parce qu'on fait du mvvm bricolé en disant que le code behind est le viewmodel
    or si tu as fait un classe viewmodel c'est là que tu dois mettre tout ce qui est bindé depuis ton UC, car il n'y a qu'un datacontext

    si tu veux des propriétés sur ton UC qui soient accessibles par celui qui utilise ton UC il faut que celles ci soit dans le code behind du XAML
    si tu veux faire un VM autre que ton code behind il faut alors répliquer ces propriétés dans le VM et quand elles changent dans la view il faut renvoyer les infos vers le viewmodel
    (enfin je vois que ca)

    perso quand je fais un usercontrol qui apporte une fonctionnalité je ne fais pas de classe de viewmodel, mais seulement me.datacontext = me


    et pour info déclarer le viewmodel dans le XAML plutôt que par code ca apporte l'IntelliSense pour les bindings en XAML (et le vm peut quand même être dispo en vb via une property qui directcast)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre actif Avatar de AcidLines
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2010
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Février 2010
    Messages : 198
    Points : 279
    Points
    279
    Par défaut
    Donc si je comprends bien,

    Soit je met mes DependencyProperties et l'implémentation des commandes dans le Code Behind du XAML,
    Soit je répercute les Dependencies Properties dans mon ViewModel dans des propriétés du ViewModel (et je suppose que je dois implémenté l'interface INotifyPropertyChanged du coup).

    Et quoi qu'il en soit je dois déclarer mon DataContext dans le code XAML pour être plus propre.

    Ai je bien compris ?

    Si c'est le cas, merci ça m'aide beaucoup.

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    Ça doit être ça oui, mais hériter de dependency object c'est mieux que d'implémenter inotify et permet d'avoir des dependency property

    Tu peux regarder aussi mvvm Light ou prism qui sont des framework mvvm car tout n'est pas présent dans le framewok .net pour bien faire du mvvm
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre actif Avatar de AcidLines
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2010
    Messages
    198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Février 2010
    Messages : 198
    Points : 279
    Points
    279
    Par défaut
    Je vais regardé ce que sont les Dependency Object, je ne connais pas cette notion encore ni comment les utiliser.

    En tout cas merci encore pour toutes ces informations.

    Je passe en mode résolu

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    tu as écrit des DependencyProperty (surement via le code snippet) et on a le droit de mettre des dependency property parce que la classe hérite de dependencyobject
    sur une DP on voit qu'il y a GetValue et SetValue qui sont appelés par les propriétés dites CLR, ces méthodes sont sur la classe
    dependencyobject
    dependencyobject via les dp ou attached properties fournit un mécanisme de stockage de valeur et de notification de changement de valeur (et tout un tas de choses en plus)
    et donc pour du binding DP est plus performant que InotifyPropertyChanged (surtout dans des collections)

    en MVVM on a souvent une classe ViewModelBase qui hérite de
    dependencyobject dont tous les viewmodels héritent (ca doit être le cas dans les sous framework mvvm que j'ai cité)

    Cours complets, tutos et autres FAQ ici : C# - VB.NET

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Méthodologie Model-View-ViewModel au sein d'une application WPF
    Par Louis-Guillaume Morand dans le forum Windows Presentation Foundation
    Réponses: 7
    Dernier message: 12/06/2015, 14h10
  2. View ViewModel et tables multiples
    Par Lionhart dans le forum C#
    Réponses: 9
    Dernier message: 07/07/2014, 09h09
  3. [MVVM] Binding View ViewModel
    Par Plawi dans le forum Windows Presentation Foundation
    Réponses: 2
    Dernier message: 18/10/2011, 11h29

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