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 :

[wpf] Gestion des Events : selection d'un item d'une treeview


Sujet :

Windows Presentation Foundation

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut [wpf] Gestion des Events : selection d'un item d'une treeview
    Bonjour à tous

    Voilà, je débute en c#, et j'ai un phénomène assez étrange qui se passe lorsque je sélectionne un item dans ma treeview : La méthode correspondante est appelée 4 fois...

    Dans le constructeur de mon contrôleur :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //Register to the SelectedIndex Routed event
    EventManager.RegisterClassHandler(typeof(Control), TreeView.SelectedItemChangedEvent,
                    (RoutedEventHandler)ItemSelected);

    Le code de la méthode appelée
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void ItemSelected(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Un item est selectionné");
    }

    Et la box s'affiche 3-4 fois... ?? o_O

    Edit : Je viens de faire le test avec :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void ItemExpanded(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("Un item est étendu !");

    et là j'ai 5 box qui s'ouvrent... Wtf...

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    C'est normal, l'évènement SelectedItemChanged est défini avec la stratégie de routage "Bubbling". Cela signifie qu'il est reçu par tous les contrôles à partir du TreeView qui le déclenche, en remontant l'arbre visuel. Comme tu as utilisé un class handler, ton handler est appelé à chaque fois qu'un contrôle reçoit l'évènement.

    En plus, normalement les class handlers sont supposés être statiques, or toi tu t'abonnes avec ce handler dans chaque instance de ta classe...

    Il vaudrait mieux s'abonner normalement à l'évènement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    treeView1.SelectedItemChanged += ItemSelected;
    Si pour une raison ou une autre tu n'as pas accès à l'instance du TreeView, tu peux effectivement utiliser un class handler, mais dans ce cas utilise un handler statique et abonne-toi dans le constructeur statique de la classe. De plus, pour que l'évènement arrête de se propager, il faut le marquer comme géré en mettant e.Handled = true.

    Lis cet article pour plus de détails sur les class handlers

  3. #3
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut
    Et bien en fait j'ai essayé de suivre le pattern MVVM, donc ce code est dans le ViewModel. Il faudrait donc que le fichier viewmodel ait la vue comme attribut et fasse quelque chose du genre maVue.monTreeview.SelectedItem ?

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Flaburgan Voir le message
    Et bien en fait j'ai essayé de suivre le pattern MVVM, donc ce code est dans le ViewModel. Il faudrait donc que le fichier viewmodel ait la vue comme attribut et face quelque chose du genre maVue.monTreeview.SelectedItem ?
    Non, en MVVM le ViewModel ne doit rien savoir de la vue. Dans certains cas, ce n'est pas très évident à gérer... par exemple dans ton cas, SelectedItem est en lecture seule et tu ne peux donc pas le binder sur le ViewModel, ce qui aurait été plus simple.

    Il y a différentes approches pour résoudre le problème...

    La plus simple est que les ViewModels qui correspondent aux items du TreeView aient une propriété IsSelected : il suffit de binder TreeViewItem.IsSelected sur cette propriété du ViewModel, et le tour est joué.

    Une autre approche est d'utiliser un attached behavior ("comportement attaché"). C'est une classe qui expose des propriétés attachées, que tu peux utiliser en XAML pour te lier à une commande de ton ViewModel qui gèrera l'évènement.


    Regarde cet article de Josh Smith sur l'utilisation de TreeView en MVVM, ça devrait te donner quelques idées

  5. #5
    Modérateur
    Avatar de Flaburgan
    Homme Profil pro
    Développeur Web
    Inscrit en
    Avril 2010
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Par défaut
    Merci, j'étais déjà tombé sur cet article mais je n'avais pas eu le courage de le parcourir entièrement car en anglais. J'y retourne avec plus de conviction ^^

    TreeViewItem gère nativement les événements selected et expanded, qu'en est-il si je veux récupérer un double clique sur une ligne ?

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Flaburgan Voir le message
    TreeViewItem gère nativement les événements selected et expanded, qu'en est-il si je veux récupérer un double clique sur une ligne ?
    Le plus simple, c'est de faire un behavior qui va lier l'évènement MouseDoubleClick à une commande du ViewModel. Concrètement:

    Code du behavior :
    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
        public static class MouseBehavior
        {
    		#region MouseDoubleClick
     
            [AttachedPropertyBrowsableForType(typeof(Control))]
            public static ICommand GetMouseDoubleClick(DependencyObject obj)
            {
                return (ICommand)obj.GetValue(MouseDoubleClickProperty);
            }
     
            public static void SetMouseDoubleClick(DependencyObject obj, ICommand value)
            {
                obj.SetValue(MouseDoubleClickProperty, value);
            }
     
            // Using a DependencyProperty as the backing store for MouseDoubleClick.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty MouseDoubleClickProperty =
                DependencyProperty.RegisterAttached(
                    "MouseDoubleClick",
                    typeof(ICommand),
                    typeof(MouseBehavior),
                    new UIPropertyMetadata(
                        null,
                        MouseDoubleClickChanged));
     
            private static void MouseDoubleClickChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
            {
                var control = o as Control;
                if (control == null)
                    return;
     
                var oldValue = (ICommand)e.OldValue;
                var newValue = (ICommand)e.NewValue;
     
                if (oldValue != null && newValue == null)
                {
                    control.MouseDoubleClick -= control_MouseDoubleClick;
                }
     
                if (newValue != null && oldValue == null)
                {
                    control.MouseDoubleClick += control_MouseDoubleClick;
                }
            }
     
            static void control_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                var control = sender as Control;
                if (control == null)
                    return;
     
                var command = GetMouseDoubleClick(control);
                if (command != null)
                {
                    if (command.CanExecute(e))
                        command.Execute(e);
                }
            }
     
            #endregion
        }
    Commande dans le ViewModel :

    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
    private ICommand _itemDoubleClickCommand;
    public ICommand ItemDoubleClickCommand
    {
        get
        {
            if (_itemDoubleClickCommand == null)
                _itemDoubleClickCommand = new DelegateCommand(OnItemDoubleClick);
     
            return _itemDoubleClickCommand;
        }
    }
     
    private void OnItemDoubleClick()
    {
        ...
    }
    Utilisation en XAML :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ...
    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="behavior:MouseBehavior.MouseDoubleClick" Value="{Binding ItemDoubleClickCommand}" />
        </Style>
    <TreeView.ItemContainerStyle>

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

Discussions similaires

  1. [WPF] Gestion du parent logique d'un item dans un ItemsControl
    Par Taenad dans le forum Windows Presentation Foundation
    Réponses: 10
    Dernier message: 15/12/2017, 01h02
  2. Gestion des events
    Par BruceBoc dans le forum SDL
    Réponses: 7
    Dernier message: 28/04/2007, 14h30
  3. [Conception] classes internes ou gestion des events
    Par TTKiBosse dans le forum Général Java
    Réponses: 2
    Dernier message: 06/12/2006, 18h25
  4. Gestion des event avec un objet ole MsExcel
    Par rdemont dans le forum Delphi
    Réponses: 3
    Dernier message: 03/07/2006, 16h08
  5. [C#] Gestion des Events d'un control Composite
    Par lord_paco dans le forum ASP.NET
    Réponses: 3
    Dernier message: 07/10/2005, 09h10

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