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 :

Application Pour Electriciens


Sujet :

Windows Presentation Foundation

  1. #1
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut Application Pour Electriciens
    bonjour à tous

    pour réaliser un software de management d'un réseau électrique je vais avoir à choisir entre deux options :
    1. utiliser une ListBox avec comme Pannel un Canevas, l’avantage premier est le Databinding
    2. Utiliser un Canevas avec des formes géométriques auxquelles je joint des Données


    après je vais voir la partie lecture à partir d'un fichier Autocad ou Excel.
    des fonction de calcul, d'Approvisionnement ...toutes ces fonctions se baseront sur l'interaction avec les objets graphiques du Canevas

    voila c'est ambitieux pour moi (je suis Ingénieur Électrotechnique et pas informaticien ).

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 562
    Points : 1 313
    Points
    1 313
    Par défaut
    le canvas est mieux d'ailleurs a ce propos je te suggère d'aller voir ces articles
    mais forcement il serait préférable d'etre plus "informaticien" lol
    http://www.codeproject.com/Articles/...-Designer-Part
    regarde les 4 parties ....

    bon courage
    IKEAS : Finalement je crois que c'est dans ses faiblesses que l'on y trouve a la fois de la force et a la fois de la richesse...
    ----------------------------------------------------
    Si vous avez du taf en wpf & design d'application sympa, contactez moi !!!!
    http://ultimatecorp.eu/wpf/

  3. #3
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    La solution 2 :
    -l'utilisation d'un panel ,ici , le canvas comme "hote" direct des controles geometriques est vivement deconseille ,car les panels n'ont pas de prop ItemqSource (collection de donnees data du reseau ) à laquelle se binder (lier)...
    Avec les panels il faut se taper Canvas.Children.Add () ou Canvas.Children.Remove() ,si par exemple les composants geomtriques visuals du reseau changent( par exemple ajout ou suppression de controls geometriques ,qui à ma connaissance vont reprenster les composants ou noeuds du reseau electrique)....
    la solution 1 par le control -ListBox ou ItemsControls avec un panel IsItemHost=true, se comporte comme suit :
    - la collection de donnees data du reseau est bindee (liee) lie à la prop ItemsSource du ListBox qui "refile" toute information de changement de data au panel canvas avec transparence ( le Canvas.Children.Add () ou Canvas.Children.Remove() est fait gratos par l'API)...

    - La personnalisation et positionnement des objets visuals est fait dans le DataTemplate du ListBox...

    - de plus chaque composant visual peut etre personnalise avec un datatemplate...
    Le listbox avec panel hote peut etre "emballe" dans un usercontrol designer ad-hoc...
    bon code...

  4. #4
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    solution 1 :
    avec le Canvas comme hôte direct + une Observablecollection dans laquelle les éventements géométriques sont sauvegardés...sa ne passe pas?

    en plus le changement sur les éléments de mon réseau ne changent pas si fréquemment sauf en mode modification.

  5. #5
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour
    avec le Canvas comme hôte direct + une Observablecollection dans laquelle les éventements géométriques sont sauvegardés...sa ne passe pas?
    Un Panel ,quel qu'il soit ,ne possede pas de prop ItemsSource pour qu'on puisse la binder avec une Observable Collection <T>....
    Le Canvas possede une prop Children en lecture seule "readonly".....
    Pour y ajouter ,supprimer ou modifier des elements de la prop Children ,il faut le faire par code....
    ¨
    voici 2 forms exemples qui illustrent le propos:

    code data commun au 2 versions du Canvas(voir ci-après) du class Node exemple:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
     
    namespace WpfCanvasNodes
    {
        public class Node:INotifyPropertyChanged 
        {
            public Node()
            {
                Key = string.Empty;
                Pos = new Point();
            }
            public Node(string pid,Point ppos):this()
            {
                Key = pid;
                Pos = ppos;
            }
            private string key;
            public string Key
            { 
                get{ return key;}
                set
                {
                    key = value; RaisePropChanged("Key");
                }
     
            }
            private Point pos ;
            public Point Pos
            {
                get { return pos; }
                set
                {
                    pos = value; RaisePropChanged("Pos");
                }
            }
     
     
     
     
            public event PropertyChangedEventHandler PropertyChanged;
            private void RaisePropChanged(string nameProp)
            {
                PropertyChangedEventHandler h = PropertyChanged;
                if (h != null ) h(this,new PropertyChangedEventArgs(nameProp));
            }
        }
        public  class Nodes:ObservableCollection<Node>
        {
            private Random rnd = new Random();
            public Nodes()
            {
                for (int i = 1; i < 6; i++)
                {
                    double x = rnd.Next(300,500);
                    double y = rnd.Next(400,500);
                    Node nd = new Node() { Key = i.ToString(), Pos = new Point(x, y) };
                    this.Add(nd);
                }
     
            }
     
     
        }
    }
    code xaml du form avec canvas hote direct designe par WinVersusCanvas:
    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
     
     
    <Window x:Class="WpfCanvasNodes.WinVersusCanvas"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:WpfCanvasNodes" 
            Title="WinVersusCanvas" Height="300" Width="300">
     
        <Grid  x:Name="grd" SizeChanged="grd_SizeChanged" >
            <Canvas
                x:Name="chart"
                Background="Transparent" Width="1000" Height="1000"
                ClipToBounds="True"
                PreviewMouseLeftButtonDown="chart_PreviewMouseLeftButtonDown" 
                PreviewMouseMove="chart_PreviewMouseMove"
                PreviewMouseRightButtonDown="chart_PreviewMouseRightButtonDown">
     
            </Canvas>
        </Grid>
    </Window>
    code behind .cs du form WinVersusCanvas avec dragging:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfCanvasNodes
    {
        /// <summary>
        /// Logique d'interaction pour WinVersusCanvas.xaml
        /// </summary>
        public partial class WinVersusCanvas : Window
        {
            private Nodes nodes = new Nodes();
            public WinVersusCanvas()
            {
                InitializeComponent();
            }
     
            private void grd_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                AddChilds();
            }
            private void AddChilds()
            {
                this.chart.Children.Clear();
                foreach (var item in nodes)
                {
                    Path path = new Path();
                    path.Fill = Brushes.AliceBlue;
                    path.Stroke = Brushes.Red;
                    EllipseGeometry geom = new EllipseGeometry();
                    geom.Center = item.Pos;
                    geom.RadiusX = 50;
                    geom.RadiusY = 50;
                    path.Data = geom;
                   this. chart.Children.Add (path);
     
                }
     
            }
            private Point mouseOffset;
            private Path selPath = null;
            private void chart_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                Canvas cnv = sender as Canvas;
                FrameworkElement element = e.Source as FrameworkElement;
                if (element == null) return;
     
                selPath = element as Path;
     
                mouseOffset = e.GetPosition(element);
     
            }
     
            private void chart_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                Canvas cnv = sender as Canvas;
                if (selPath == null) return;
                Point point = e.GetPosition(cnv);
     
                // Move the element.
                Canvas.SetLeft(selPath, point.X-mouseOffset.X );
                Canvas.SetTop(selPath, point.Y-mouseOffset.Y );
     
            }
     
            private void chart_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                Canvas cnv = sender as Canvas;
                if (selPath == null) return;
     
                Point point = e.GetPosition(cnv);
     
                // Move the element.
                Canvas.SetLeft(selPath, point.X - mouseOffset.X);
                Canvas.SetTop(selPath, point.Y - mouseOffset.Y);
     
     
                selPath = null;
     
            }
        }
    }
    -

    code xaml du form avec canvas hote d'un ListBox designe par WinVersusListBox:
    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
     
    <Window x:Class="WpfCanvasNodes.WinVersusListBox"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfCanvasNodes" 
            Title="WinVersusListBox" Height="350" Width="525">
        <Window.Resources>
            <local:Nodes  x:Key="datasource"/>
            <DataTemplate x:Key="templatenode" DataType="{x:Type local:Node}">
               <!--czanvas layer est layere ou superpose  au dessus du canvas hote -->
                <!--ll permet le positionnement precis du texte et autres ornements eventuels-->
                <Canvas    Background="Transparent"   >
                    <!--node 1-->
                    <Path
                        Fill="AliceBlue" Stroke="Red" 
                        PreviewMouseLeftButtonDown="Path_PreviewMouseLeftButtonDown"
                        PreviewMouseMove="Path_PreviewMouseMove"        
                        PreviewMouseRightButtonDown="Path_PreviewMouseRightButtonDown" >
     
                      <Path.Data>
                         <EllipseGeometry Center="{Binding Path=Node.Pos,Mode=TwoWay}"  
                                             RadiusX="50" RadiusY="50"/>
                        </Path.Data>
                    </Path>
                    <TextBlock 
                        Canvas.Left="{Binding Path=Pos.X}"
                        Canvas.Top ="{Binding Path=Pos.Y}"
                        Text="{Binding Path=Key}"/>
                </Canvas > 
     
            </DataTemplate>
     
        </Window.Resources>
        <Grid>
            <ListBox 
                ItemTemplate="{StaticResource templatenode}" 
                ItemsSource="{Binding Source={StaticResource datasource}}"
                >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Background="Transparent" 
                            ClipToBounds="True" 
                            IsItemsHost="True" Width="1000" Height="1000"               
                    />
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
                    <ListBox.ItemContainerStyle>
                        <Style TargetType="{x:Type ListBoxItem }">
                            <Setter Property="Canvas.Left" Value="{Binding Path= Pos.X}"/>
                            <Setter Property="Canvas.Top" Value="{Binding Path= Pos.Y}"/>
                        </Style>
                    </ListBox.ItemContainerStyle>
                </ListBox>
     
        </Grid>
    </Window>
    et son code behind .cs :

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfCanvasNodes
    {
        /// <summary>
        /// Logique d'interaction pour WinVersusListBox.xaml
        /// </summary>
        public partial class WinVersusListBox : Window
        {
            public WinVersusListBox()
            {
                InitializeComponent();
            }
     
            private Point mouseOffset; 
            private Path selPath = null;
            private void Path_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
     
     
                FrameworkElement element = e.Source as FrameworkElement;
                if (element == null) return;
     
                    selPath = element as Path;
                    mouseOffset = e.GetPosition(element); 
                    selPath.CaptureMouse();
     
            }
            private void Path_PreviewMouseMove(object sender, MouseEventArgs e)
            {
     
                if (selPath == null) return;
                Point point = e.GetPosition(selPath.Parent as Canvas  );
     
                // Move the element.
                Canvas.SetLeft(selPath, point.X);
                Canvas.SetTop(selPath,  point.Y);
     
            }
     
     
            private void Path_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
     
                if (selPath == null) return;
     
                Point point = e.GetPosition(selPath.Parent as Canvas);
     
                // Move the element.
                Canvas.SetLeft(selPath, point.X);
                Canvas.SetTop(selPath, point.Y);
     
                selPath.ReleaseMouseCapture();
                selPath = null;
     
            }
        }
    }
    bon code....

  6. #6
    Membre confirmé Avatar de Issam
    Inscrit en
    Mars 2002
    Messages
    578
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations forums :
    Inscription : Mars 2002
    Messages : 578
    Points : 604
    Points
    604
    Par défaut
    Bonjour,


    a ta place j'utiliserais des composants spécialisés diagramme, comme celui de syncfusion

    http://www.syncfusion.com/products/wpf/diagram

    et c'est gratuit ! avec la licence community

  7. #7
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    Citation Envoyé par Issam Voir le message
    Bonjour,


    a ta place j'utiliserais des composants spécialisés diagramme, comme celui de syncfusion

    http://www.syncfusion.com/products/wpf/diagram

    et c'est gratuit ! avec la licence community
    eu...Free? : je ne vois pas ou!

  8. #8
    Membre confirmé Avatar de Issam
    Inscrit en
    Mars 2002
    Messages
    578
    Détails du profil
    Informations personnelles :
    Âge : 48

    Informations forums :
    Inscription : Mars 2002
    Messages : 578
    Points : 604
    Points
    604

  9. #9
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    y a ça aussi


    video mliha mais pourquoi elle utilise : dependencyObect pour node? alors que ce n'est pas un controle!

  10. #10
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    j'ai suivi exactement la meme idée pour déjà commencer à comprendre le truc voici le XAML :

    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
     
    <ListBox Name="ListBoxNodes" Background="Transparent" Grid.Row="1">
     
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas Background="Transparent" Name="canvasNodes"
                                MouseLeftButtonDown="canvasNodes_MouseLeftButtonDown"
                                Loaded="canvasNodes_Loaded"  />
                    </ItemsPanelTemplate>
     
                </ListBox.ItemsPanel>
     
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Rectangle MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"  Width="50" Height="50" Fill="Black"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
     
     
                <ListBox.ItemContainerStyle>
                    <Style>
                        <Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
                        <Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
                    </Style>
                </ListBox.ItemContainerStyle>
     
     
            </ListBox>
    je n'arrive pas à identifier mon Item pour procéder à des opérations sur lui et le passage de la géométrie vers les Data avec le DataContext et bien je ne maitrise pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     public MainWindow()
            {
                InitializeComponent();
                mygraph = new Graph();
     
                mygraph.AddNode(200, 50);
                mygraph.AddNode(400, 200);
     
               this.ListBoxNodes.ItemsSource = mygraph.Nodes;
     
     
            }
    et puis l'évènement "MouseLeftButtonDown" :
    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
     
    private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
     
                Rectangle Rect = sender as Rectangle;
                if (Rect != null)
                {
     
                    Node ND = Rect.DataContext as Node; //ici sa ne passe pas, sa me donne un new Node() au lieu de prendre le Node courant
                    if (ND != null)
                    {
                       this.NodeID.Text = ND.ID.ToString(); //sa me donne -14
     
                    }
                }
     
     
            }
    les Classes Node et Graph

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
     
     
    public class Node : INotifyPropertyChanged
        {
     
            private int _id;
            private double _x ;
            private double _y;
     
        public Node(double x,double y)
        {
            X = x;
            Y = y;
            ID=_id=-14; //juste pour voir
     
        }
     
            public event PropertyChangedEventHandler PropertyChanged;
     
            private void OnPropertyChanged(String infopropriety)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(infopropriety));
                }
            }
     
            //----------Propriétés---
     
            public double X
            {
                get { return this._x; }
     
                set
                {
                    if (value != this._x)
                    {
                        this._x = value;
                        OnPropertyChanged("X");
                    }
                }
            }
     
            public double Y
            {
                get { return this._y; }
     
                set
                {
                    if (value != this._y)
                    {
                        this._y = value;
                        OnPropertyChanged("Y");
                    }
                }
            }
     
            public int ID
            {
                get { return this._id; }
     
                set
                {
                    if (value != this._id)
                    {
                        this._id = value;
                        OnPropertyChanged("ID");
                    }
                }
            }
     
        }
     
     
    public class Graph
        {
     
            public ObservableCollection<Node> Nodes { get; private set; }
     
            public int collectionIndex;
     
            public Graph()
            {
                this.Nodes = new ObservableCollection<Node>();
                this.collectionIndex = 0;
            }
     
            public void AddNode(double x, double y)
            {
                Node thisnode = new Node(x, y);
                this.collectionIndex++;
                thisnode.ID = this.collectionIndex;
                this.Nodes.Add(new Node (x,y));
     
            }
     
     
            public void AddNode(Node ND)
            {
                this.collectionIndex++;
                ND.ID = this.collectionIndex;
                this.Nodes.Add(ND);
     
     
            }
     
     
        }

  11. #11
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    code revu avec
    Canvas "itemhost" dans un ListBox ...
    il faut utiliser PreviewMouseDown,PreviewMouseMove au niveau du Canvas "itemhost"

    Toute modif des coords d'un "item data" se repercute sur le Shape ou Control....à cause du binding (liaison)


    code data sans changemet.............

    code xaml du form :

    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
     
     
    <Window x:Class="WpfAppGraphNode.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1" Height="350" Width="525" Loaded="Window_Loaded">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel>
     
                <TextBlock Text="{Binding ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding X}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Y}" Margin="5"></TextBlock>
            </DockPanel>
            <!--correction binding-->
            <ListBox 
                Name="ListBoxNodes" Background="Transparent" Grid.Row="1"
                ItemsSource="{Binding }">
                <!--les handlers mouse doivent etre fait le panel hote-->
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas
                            IsItemsHost="true"
                            ClipToBounds="true"
                            Background="Transparent" Name="canvasNodes"
                          PreviewMouseLeftButtonDown="canvasNodes_PreviewMouseLeftButtonDown"
                            PreviewMouseMove="canvasNodes_PreviewMouseMove"
                            PreviewMouseRightButtonDown="canvasNodes_PreviewMouseRightButtonDown">
                        </Canvas>
                    </ItemsPanelTemplate>
     
                </ListBox.ItemsPanel>
     
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Rectangle Width="50" Height="50" Fill="Black"
     
                                   />
                    </DataTemplate>
                </ListBox.ItemTemplate>
                <!--c'est le listboxitem (qui contient le rectangle) dont 
                nous lions ses prop attaches Canvas.LeftCanvas.Left &&  Canvas.Top à x,y du node -->
                <!--toute modif sur x et y via code ou saisie se repercute sur le listbox donc sur le rectangle-->
                <ListBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ListBoxItem}">
                        <Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
                        <Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
                    </Style>
                </ListBox.ItemContainerStyle>
     
     
            </ListBox>
        </Grid>
    </Window>
    code .cs pour le 1er cas:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfAppGraphNode
    {
        /// <summary>
        /// Logique d'interaction pour Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            private Graph mygraph;
            public Window1()
            {
                InitializeComponent();
                mygraph = new Graph();
     
                mygraph.AddNode(200, 50);
                mygraph.AddNode(400, 200);
                //correction
                this.DataContext = mygraph.Nodes;
            }
            private Rectangle selRect = null;
            private void canvasNodes_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                selRect = e.OriginalSource as Rectangle;
                if (selRect == null) return;
     
            }
            private void canvasNodes_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (selRect == null) return;
                Point p = e.GetPosition(selRect.Parent as Canvas);
     
     
                //update datacontext (se repercute sur listbox item)
                Node node = selRect.DataContext as Node;
                node.X = p.X;
                node.Y = p.Y;
            }
            private void canvasNodes_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (selRect == null) return;
     
                Point p = e.GetPosition(selRect.Parent as Canvas);
     
                //update datacontext 
                Node node = selRect.DataContext as Node;
                node.X = p.X;
                node.Y = p.Y;
     
     
                selRect = null;
     
            }
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
     
            }
     
     
     
        }
    }

    code data revu pour gerer un Graph (graphis) avec Arcs et utilisation des Path ( decrit par des objets Geometry plus adaptes pour decrier des "connectors" lies aux "nodes" ):

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.Windows;
     
    namespace WpfAppGraphNode
    {
     
     
        public class Node : INotifyPropertyChanged
        {
     
            private int _id;
            private double _x;
            private double _y;
            public Node()
            {
                ID = 0;
                X = 100;
                Y = 75;
            }
            public Node(double x, double y):this()
            {
                X = x;
                Y = y;
            }
            public Node(int pid, double x, double y):this(x,y)
            {
                ID = pid;
                X = x;
                Y = y;
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
     
            private void OnPropertyChanged(String infopropriety)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(infopropriety));
                }
            }
     
            //----------Propriétés---
     
            public double X
            {
                get { return this._x; }
     
                set
                {
                    if (value != this._x)
                    {
                        this._x = value;
                        location.X  = this._x; 
                        OnPropertyChanged("X");
                    }
                }
            }
     
            public double Y
            {
                get { return this._y; }
     
                set
                {
                    if (value != this._y)
                    {
                        this._y = value;
                        location.Y = this._y;
                        OnPropertyChanged("Y");
                    }
                }
            }
            /// <summary>
            /// rajout prop Location en double
            /// </summary>
            private Point location;
            public Point Location
            {
                get { return location; }
                set
                {
                    if (value != this.location)
                    {
                       this.location = value;
                       this._x  = this.location.X;
                       this._y = this.location.Y;
                        OnPropertyChanged("Location");
                    }
                } 
     
            }
            public int ID
            {
                get { return this._id; }
     
                set
                {
                    if (value != this._id)
                    {
                        this._id = value;
                        OnPropertyChanged("ID");
                    }
                }
            }
     
        }
     
     
     
    }
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    using System.Windows;
     
    namespace WpfAppGraphNode
    {
        public class GraphBis : INotifyPropertyChanged
        {
     
     
            public ObservableCollection<Node> Nodes { get;  set; }
            public ObservableCollection<Arc> Arcs { get; set; }
     
     
     
     
            public GraphBis()
            {
     
                this.Nodes = new ObservableCollection<Node>();
                this.Arcs = new ObservableCollection<Arc>(); 
            }
            public void AddArc(Node nd1,Node  nd2)
            {
     
                    Arc larc = new Arc();
                    Nodes.Add(nd1);
                    Nodes.Add(nd2);
                    nd1.ID = Nodes.IndexOf(nd1);
                    nd2.ID = Nodes.IndexOf(nd2);
                    larc.Node1 = nd1;
                    larc.Node2 = nd2;
                    Arcs.Add(larc);
     
     
            }
            public void AddArcs(List<Arc> items)
            {
                foreach (var item in items)
                {
                    this.AddArc(item.Node1,item.Node2);
                }
     
            }
     
     
            public event PropertyChangedEventHandler PropertyChanged;
     
            private void OnPropertyChanged(String infopropriety)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(infopropriety));
                }
            }
     
        }
    }
    code xaml du form utilisateur:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    <Window x:Class="WpfAppGraphNode.Window2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfAppGraphNode" 
            Title="Window2" Height="300" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel>
     
                <TextBlock Text="{Binding Path=Node1.ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Node1.Location}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Node2.ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Node2.Location}" Margin="5"></TextBlock>
            </DockPanel>
            <!--correction binding-->
            <ListBox 
                Name="ListBoxArcs" Background="Transparent" Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding }">
                <!--les handlers mouse doivent etre fait le panel hote-->
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas
                            IsItemsHost="true"
                            ClipToBounds="true"
                            Background="Transparent" Name="canvasNodes"
                            PreviewMouseLeftButtonDown="canvasNodes_PreviewMouseLeftButtonDown"
                            PreviewMouseMove="canvasNodes_PreviewMouseMove"
                            PreviewMouseRightButtonDown="canvasNodes_PreviewMouseRightButtonDown">
                        </Canvas>
                    </ItemsPanelTemplate>
     
                </ListBox.ItemsPanel>
     
                <ListBox.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:Arc}">
                        <Canvas >
                            <Path
                                Stroke="Red" Fill="blue">
                                <Path.Data>
                                    <EllipseGeometry Center="{Binding Path=Node1.Location, Mode=TwoWay}" 
                                                     RadiusX="25" RadiusY="25"/>
                                </Path.Data>
     
                            </Path>
                            <Path 
                                Stroke="Yellow"  Fill="Magenta" >
                                <Path.Data>
                                    <EllipseGeometry Center="{Binding Path=Node2.Location,Mode=TwoWay}" 
                                                     RadiusX="25" RadiusY="25"/>
                                </Path.Data>
     
                            </Path>
                            <Path 
                                Stroke="Black" StrokeThickness="2.0" >
                                <Path.Data>
                                    <LineGeometry
                                        StartPoint="{Binding Path=Node1.Location,Mode=TwoWay}"
                                        EndPoint="{Binding Path=Node2.Location,Mode=TwoWay}"
     
                                                  />
                                </Path.Data>
                            </Path>
                        </Canvas >
                    </DataTemplate>
                </ListBox.ItemTemplate>
     
                <ListBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ListBoxItem}">
                        <Setter Property="Canvas.Left" Value="{Binding Path=Node1.X}"/>
                        <Setter Property="Canvas.Top" Value="{Binding Path=Node1.Y}"/>
                    </Style>
                </ListBox.ItemContainerStyle>
     
     
            </ListBox>
        </Grid>
    </Window>
    code .cs du form:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfAppGraphNode
    {
        /// <summary>
        /// Logique d'interaction pour Window2.xaml
        /// </summary>
        public partial class Window2 : Window
        {
            private GraphBis mygraph;
            public Window2()
            {
                InitializeComponent();
                mygraph = new GraphBis();
                GetArcs();
     
                //correction
                this.DataContext = mygraph.Arcs;
            }
            private void GetArcs()
            {
                List<Arc> liste = new List<Arc>();
                for (int i = 5; i < 11; i++)
                {
                    Node nd1 = new Node() {X = rndPoint.X, Y = rndPoint.Y };
                    Node nd2 = new Node() {X = rndPoint.X, Y = rndPoint.Y };
                    Arc larc = new Arc() { Node1 = nd1, Node2 = nd2 };
                   liste.Add(larc);
                }
                mygraph.AddArcs(liste);
     
            }
            private Random rnd = new Random();
            private Point rndPoint
            {
                get
                {
                    Point p = new Point() { X = rnd.Next(300, 500), Y = rnd.Next(200, 500) };
                    return p;
                }
            }
            private Path selPath = null;
            private void canvasNodes_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                selPath = e.OriginalSource as Path;
                if (selPath == null) return;
     
            }
     
            private void canvasNodes_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (selPath == null) return;
                Point p = e.GetPosition(selPath.Parent as Canvas);
     
     
                //repercute sur datacontext 
                EllipseGeometry ellip = selPath.Data as EllipseGeometry ;
     
                ellip.Center = p;
     
            }
     
            private void canvasNodes_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            { if (selPath == null) return;
     
                Point p = e.GetPosition(selPath.Parent as Canvas);
     
                //repercute sur datacontext 
                EllipseGeometry ellip = selPath.Data as EllipseGeometry;
     
                ellip.Center = p;
     
     
                selPath = null;
     
            }
        }
    }
    l'utilisation des geometry derives de Shape (rectangle,ellipse,line ) a de seieuses limitations en matiere de positionnement sur le canvas....
    Pour avoir un Line "custom" disposant des props type Point ,ou des des formes geometriques plus elabores il faut un custom shape derivee de shape.... par heritage....
    bon code....

  12. #12
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    merci pour ta réponse
    mon code marche et ce en affichant les rectangle dans leurs coordonnées, et j'ai même pas utiliser IsItemhost=True !
    en utilisant l’événement sourie à partir d'ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Rectangle MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"  Width="50" Height="50" Fill="Black"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
    j'ai bien une identification d'un rectangle, et en convertant avec "as" j'ai bien un objet Node...mais pas l'item courant.

    j'utilise le rectangle en espérant ne pas utiliser un control ou un ensemble de control qui vont alourdir le dessin de centaines d'Item, car en utilisant un controle je vais pouvoir utiliser l’événement Mouse du control mais aussi et surtout à l'Item, mais dés le départ je vais alourdir chaque DataTemplate et mes Items.
    Après je vais utiliser le TargetType sur le DataTemplate pour dessiner un Vertex en le considérant comme lui même un item

    mon problème

  13. #13
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Tout d'abord tu n'as pas les bases du WPF...
    Secundo tu poses une question et tu te reponds à toi-meme ,grand travers pour apprendre le WPF..
    Tertio tu ne lis pas attentivement le code pour le comprendre....
    Cela fait une discussion de sourds qui ne menes à rien....

    Ton code du ListBox.ItemTemplate est pipe car il lui manque l'essentiel....
    Le rectangle est ...un control et si tu as des centaines de Rectangles ca va ramer .....

    voilà ce que j'ai à te repondre.....

  14. #14
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    je te remercie encore une fois pour ta réponse, et je te confirme que j'ai bien lu ton code, mais je voulais tester quelque chose de moins élaborée au début , c'est pour cela que je n'ai mis que des "Node", j'avais expliqué que je voulais joindre les "Arc" après en utilisant une idée différente de la tienne, je voilais tester et je posait des questions sur cette façon de faire, je ne mettais pas mon semblant de code en concurrence avec le tien.

    et oui je suis très débutant en WPF et même en c#.

    je remercie toujours toute personne me donnant une info et 1000 mercis.


    j'ai une exception :
    Une exception non gérée du type 'System.NullReferenceException' s'est produite dans GraphWPFPath.exe
    Informations supplémentaires*: La référence d'objet n'est pas définie à une instance d'un objet.

    c'est lors du Drag de l’ellipse là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     EllipseGeometry ellip = selPath.Data as EllipseGeometry ;
    je n'ai pas compris comment tu récupère le Data, ici Item ARC :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     //repercute sur datacontext 
     EllipseGeometry ellip = selPath.Data as EllipseGeometry;
    à Ok comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Arc myArc = selPath.DataContext as Arc;
    dessiner les Arc revient à dessiner plusieurs fois un noeud commun

  15. #15
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    re


    c'est lors du Drag de l’ellipse là :
    Tu aurais du corriger ,car dans le DataTemplate il y a le LineGeometry encapsule dans un Path et comme on selectionne un Path ,si on tombe sur lui on a une exception car SelPath.Data contient un LineGeometry et fatalement on leve une Exception...
    Comme le code a ete ecrit à 2 heures du matin, il suffisait de rajouter ceci pour eviter l'exception:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
     if (ellip == null) return;
    Ensuite :

    je n'ai pas compris comment tu récupère le Data, ici Item ARC :
    je travaille avec le "revers" du DataContext c'.à.d je modifie le Centre de l'Ellipse..
    Lequel est "binde"(pieds et poings liés) à la prop Location de l'item.....Le binding etant Biderectionnel ,cela revient au meme !!!
    Maintenant pourquoi le Centre de l'ellipse ?
    Parce que c'est le sommet du Vertex et que l'EllipseGeometry n'as pas de prop DataContext....

    L'utilisation d'un EllipseGeometry est justifie par sa prop Center de type Point..
    Son Path container n'ayant pas comme son cousin Rectangle de prop Point auquel on puisse se Bindier ....

    Le DataContext de l'Arc est ambigu ,parce qu'il y a 2 nodes et le selected Path ne fournit aucune prop indiquant quel item Node a ete "clique"....

    Voilà ....


    dessiner les Arc revient à dessiner plusieurs fois un noeud commun
    Effectivement dans l'exemple "simpliste" donne!!!
    Pour resoudre cette question fort epineuse ,inherente,aux diagrammes ,graph ,orgchart et ne dessiner qu'un Node il faut ce qu'il faut:

    1/ Un Graph plus elabore c.à.d normalise :
    - avec un Dictionnary à Cle pour les Nodes ...Un dictionary "storer" un Node unique identifie par sa cle ...
    - un Node "root" ou "racine" auquel accroche les futurs nodes descendants....
    - l'ajout d'arc est subordonne à l'existence des 2 nodes ou au moins à l'un d'eux
    -le graph d'exemple (ci-après ) illustre cette problematique dans GraphUtil...

    2/ Pour ne pas "dessiner" un Node 2 fois il faut utiliser un CompositeCollection qui contient 2 ContainerCollection
    - un ContainerCollection pour les Nodes
    - un ContainerCollection pour les Arcs
    - les 2 ContainerCollections sont merges ensuite dans le CompositeCollection qui sera assigne au DataContext du Form
    -de plus 2 DataTemplate dans la prop Resources du ListBox sont necessaires :
    -un pour le class data Node
    -un pour le class data Arc ...
    sans les attributs Key...
    Le Listbox reconnaitra les siens (comme le Bon Dieu à la Saint Barthelemy !!!)....

    Ca se complexifie n'est ce pas mais c'est le prix à payer .....!!!

    code data revu du GraphUtil :

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
     
    namespace WpfAppGraphNode2
    {
        public class GraphUtile : INotifyPropertyChanged
        {
            // le conmpteur de node doit etre static
            // pour eviter la duplication d'ID
            // il est private et par suite il ne peut servir de "key" pour le dictionnary
            private static int counter;
           //  le noeud "racine" est auto-genere
            // tout  noeud peut l'avoir comme ancetre direct ou lointain...
            // porte un nom specifique "ROOT" ou whatever you want
     
            private Node root = null;
     
            // le "key" des nodes est le nom
            private Dictionary<string, Node> data = null;
            public GraphUtile()
            {
                counter = 0;
                data = new Dictionary<string, Node>();
                Nodes = new ObservableCollection<Node>();
                Arcs = new ObservableCollection<Arc>();
                AddRoot();
     
            }
            #region Private Method
            private void AddRoot()
            {
                root = new Node() { Name = "ROOT", X = 120.0, Y = 70.0 };
                root.ID = counter;
                this.data.Add(root.Name, root);
                this.Nodes.Add(root);
            }
            #endregion
     
            #region Public Methods
            public void AddArc(Node nd1, Node nd2)
            {
                if (data.ContainsKey(nd1.Name ) && data.ContainsKey(nd2.Name ))
                {
                    Arc larc = new Arc();
                    larc.Node1 = data[nd1.Name ];
                    larc.Node2 = data[nd2.Name ];
                    Arcs.Add(larc);
                }
                if (data.ContainsKey(nd1.Name ) && !data.ContainsKey(nd2.Name))
                {
                    counter++;
                    nd2.ID=counter;
                    data.Add(nd2.Name , nd2);
                    Nodes.Add(nd2);
     
                    Arc larc = new Arc();
                    larc.Node1 = data[nd1.Name ];
                    larc.Node2 = data[nd2.Name];
                    Arcs.Add(larc);
                }
                if (!data.ContainsKey(nd1.Name ) && data.ContainsKey(nd2.Name ))
                {
                    counter++;
                    nd1.ID = counter;
                    data.Add(nd1.Name, nd1);
                    Nodes.Add(nd1);
     
                    Arc larc = new Arc();
                    larc.Node1 = data[nd2.Name ];
                    larc.Node2 = data[nd1.Name];
                    Arcs.Add(larc);
                }
     
            }
            public void AddArcs(List<Arc> items)
            {
                foreach (var item in items)
          	    {
                    AddArc(item.Node1 , item.Node2 );
    	        }
     
     
            }
            public void AddArc(string key1, double x1, double y1, string key2, double x2, double y2)
            {
                Node nd1 = new Node(key1, x1, y1);
                Node nd2 = new Node(key2, x2, y2);
                AddArc(nd1, nd2);
     
            }
            public void Clear()
            {
                this.data.Clear();
                this.Arcs.Clear();
                this.Nodes.Clear();
            }
            #endregion
            #region Properties
            private ObservableCollection<Arc> arcs;
     
            public ObservableCollection<Arc> Arcs
            {
                get { return arcs; }
                set { arcs = value; RaisePropChanged("Arcs"); }
            }
     
            private ObservableCollection<Node> nodes;
            public ObservableCollection<Node> Nodes
            {
                get { return nodes; }
                set { nodes = value; RaisePropChanged("Nodes"); }
            }
            #endregion
     
     
     
     
     
            #region Public Event 
            public event PropertyChangedEventHandler PropertyChanged;
            private void RaisePropChanged(string nameProp)
            {
                PropertyChangedEventHandler h = PropertyChanged;
                if (h != null) h(this, new PropertyChangedEventArgs(nameProp));
            }
            #endregion
     
     
        }
     
    }
    code data du SimpleGraph (heritier direct de GraphUtil ) et comment l'utiliser avec un class auxiliaire RouteCity à des fins d'illustration :

    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
     
      public class RouteCity
        {
            public RouteCity(string cty1, string cty2)
            {
                City1 = cty1;
                City2 = cty2;
            }
     
            public string City1 { get; set; }
            public string City2 { get; set; }
        }
     
        public class SimpleGraph : GraphUtile
        {
            private List<RouteCity> tableRoute = new List<RouteCity>();
     
            public SimpleGraph()
                : base()
            {
                tableRoute = GetRoute();
     
                foreach (RouteCity route in tableRoute)
                {
                    this.AddArc(
                        route.City1,rndPosition.X, rndPosition.Y,
                        route.City2,rndPosition.X ,rndPosition.Y );
                }
            }
            private List<RouteCity> GetRoute()
            {
                List<RouteCity> l = new List<RouteCity> {
               new RouteCity("ROOT", "Paris"),
               new RouteCity("Paris", "Chartres"),
               new RouteCity("Chartres", "Le Mans"),
               new RouteCity("Le Mans", "Tours"),
               new RouteCity("Tours", "Nantes"),
               new RouteCity("Paris", "Dijon"),
               new RouteCity("Dijon", "Lyon"),
               new RouteCity("Paris", "Rouen"),
               new RouteCity("Paris", "Arras"),
               new RouteCity("Arras", "Lille"),
               new RouteCity("Rouen","Arras")
                };
                return l;
            }
            private Random rnd = new Random();
            private Point rndPosition
            {
                get
                {
                    Point p = new Point() { X = rnd.Next(100, 500), Y = rnd.Next(100, 500) };
                    return p;
                }
            }
        }
    code xaml du form utilisateur:

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
     
    <Window x:Class="WpfAppGraphNode2.Window5"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfAppGraphNode2" 
            Title="Window5" Height="300" Width="300">
     
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel>
                <TextBlock Text="{Binding Path=Name}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Location}" Margin="5"></TextBlock>
            </DockPanel>
             <ListBox 
     
                Name="ListBoxArcs" 
                Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding }" >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                          Name="canvasNodes"
                          IsItemsHost="True" ClipToBounds="True" Background="LightGray" 
                         PreviewMouseLeftButtonDown="canvasNodes_PreviewMouseLeftButtonDown"
                         PreviewMouseMove="canvasNodes_PreviewMouseMove"
                         PreviewMouseRightButtonDown="canvasNodes_PreviewMouseRightButtonDown" >
     
     
                        </Canvas>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
                <ListBox.Resources>
                    <DataTemplate 
                        DataType="{x:Type local:Node}">
                        <Canvas  Background="Transparent" >
                            <Path
                                Stroke="Red" Fill="blue">
                                <Path.Data>
                                    <EllipseGeometry 
                                        Center="{Binding Path=Location, 
                                        Mode=TwoWay}" 
                                        RadiusX="25" RadiusY="25"/>
                                </Path.Data>
                            </Path>
                            <TextBlock 
                                Foreground="Yellow" 
                                Background="Red" 
                                Canvas.Left="{Binding Path=Location.X,Mode=TwoWay}"
                                Canvas.Top="{Binding Path=Location.Y,Mode=TwoWay}"
                                Text="{Binding Path=Name}"/>
                        </Canvas>
                    </DataTemplate>
                    <DataTemplate  
                        DataType="{x:Type local:Arc}">
                        <Canvas  Background="Transparent" >
                            <Path
                                Stretch="None" 
                                Stroke="Black" StrokeThickness="2.0">
                                <Path.Data>
                                    <LineGeometry
                                        StartPoint="{Binding Path=Node1.Location,Mode=TwoWay}"                                       
                                        EndPoint="{Binding Path=Node2.Location,Mode=TwoWay}">
                                    </LineGeometry>
                                </Path.Data>
                            </Path>
                        </Canvas>
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
        </Grid>
    </Window>
    code behind .cs:

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfAppGraphNode2
    {
        /// <summary>
        /// Logique d'interaction pour Window5.xaml
        /// </summary>
        public partial class Window5 : Window
        {
            private SimpleGraph mygraph;
            private CompositeCollection compositeNodeArcs = null;
            private CollectionContainer containterNodes = null;
            private CollectionContainer containerArcs = null;
            public Window5()
            {
                InitializeComponent();
                mygraph = new SimpleGraph();
     
                containterNodes = new CollectionContainer() { Collection = mygraph.Nodes };
                containerArcs = new CollectionContainer() { Collection= mygraph.Arcs };
     
                compositeNodeArcs = new CompositeCollection();
                compositeNodeArcs.Add(containerArcs);
                compositeNodeArcs.Add(containterNodes);
     
     
                this.DataContext = compositeNodeArcs;
            }
            private Path selPath = null;
            private void canvasNodes_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                selPath = e.OriginalSource as Path;
                if (selPath == null) return;
     
                //azctiver la capture par le  path
                selPath.CaptureMouse();
            }
     
            private void canvasNodes_PreviewMouseMove(object sender, MouseEventArgs e)
            {
     
                if (selPath == null) return;
                Point p = e.GetPosition(selPath);
     
                //le binding est bidirection grace à Mode=TwoWay 
                EllipseGeometry ellip = selPath.Data as EllipseGeometry;
                if (ellip == null) return;
     
                ellip.Center = p;
     
            }
     
            private void canvasNodes_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (selPath == null) return;
     
                //liberer la capture souris par un click droit 
                selPath.ReleaseMouseCapture();
     
                selPath = null;
     
            }
     
     
     
     
        }
    }
    NB: Path , Rectangle ,Line ,Ellipse sont des descendants de Shape et ont une charge identique en memoire et rendu ....Mais leur principal inconvenient est qu'ils pas de props Points pour le positionnement précis...

    Plus de 200 elements peuvent faire ramer l'application....
    Des objets plus legers ,"freezables" ou "gelables" (figes en memoire et ne pouvant etre modifies),pour le dessin sont les collections du class DrawingVisual couples à l'utilisation d'objets du class Drawing ...
    Mais cela necessite de se doter de DrawingVisual "custom" approvisionnes par des objets Drawing (DrawingGeometry,DrawingImage etc...)' crees dans des dictionary xaml....
    bon code....

  16. #16
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    je viens de lire..

    tu as utilisé deux DataTemple et c'est très évolutif comme code c'est exactement ce qu'il me faut..



    en faite je crois que tes messages sont ceux qui creusent le plus le sujet tu devrai faire une sorte de Tuto, certain utilise des thumb (http://www.codeproject.com/Articles/...-Designer-Part).

    pour toi c'est peut être très simple mais vu que c'est rare sur le Net ..et bien Merci..

    je vais m'y mettre..

    pour les "CompositeCollection" est un outil très important car il remplacera un peut un DataSet ou du moins une partie visuelle , bien sure j'ai une peur bleu rien que de nommer le nom MVVM..mais quant on ose dire je vais faire un software de gestion des réseaux..je suis obligé d'y passer.
    pour la CompositeCollection...un lien : http://blog.pmunin.com/2012/02/xaml-...ollection.html.
    pour le : Dictionary c'est ma première fois .

  17. #17
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Re
    j'ai lu le lien en question mais le probleme dont se plaint le blogueur survient lorsque le DataContext est binde au CompositeCollection et ses ConainerCollections en Xaml et non dans le code comme dans l'exemple donne(datacontext mis dans le code)...

    En MVMM le DataContext est toujours mis dans le code.....

    De toute facon dans notre cas il existe une autre alternative equivalente :
    - "layerer" 2 ListBoxes ,le 1er binde aux Nodes ,le 2eme aux Arcs...et le DataContext du Form binde au Graph...
    - un Grid englobant assure la superposition exacte des 2 ListBoxes...
    - le 2eme ListBox && son canvas panel hot avec un Background transparent
    - ils sont aussi "pass through" vis à vis du HitTest souris (les events passent au travers)....

    code xaml revu du form versus 2 listboxes "layeres":
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
     
     
    <Window x:Class="WpfAppGraphNode2.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:local="clr-namespace:WpfAppGraphNode2" 
            Title="Window1" Height="300" Width="300">
     
        <!--Grid assure la superposistion "exacte" des 2 LisbBoxes comme 2 calques-->
        <Grid >
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel>
                <TextBlock Text="{Binding Path=Name}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Location}" Margin="5"></TextBlock>
            </DockPanel>
     
            <ListBox 
     
                Name="ListBoxNodes"  Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Path=Nodes}" >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Name="canvasNodes"
                            IsItemsHost="True" ClipToBounds="True" Background="LightGray" 
                            PreviewMouseLeftButtonDown="canvasNodes_PreviewMouseLeftButtonDown"
                            PreviewMouseMove="canvasNodes_PreviewMouseMove"
                            PreviewMouseRightButtonDown="canvasNodes_PreviewMouseRightButtonDown" >
                        </Canvas>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
                <ListBox.Resources>
                    <DataTemplate 
                        DataType="{x:Type local:Node}">
                        <Canvas  Background="Transparent" >
                            <Path
                                Stroke="Red" Fill="blue">
                                <Path.Data>
                                    <EllipseGeometry 
                                        Center="{Binding Path=Location, 
                                        Mode=TwoWay}" 
                                        RadiusX="25" RadiusY="25"/>
                                </Path.Data>
                            </Path>
                            <TextBlock 
                                Foreground="Yellow" 
                                Background="Red" 
                                Canvas.Left="{Binding Path=Location.X,Mode=TwoWay}"
                                Canvas.Top="{Binding Path=Location.Y,Mode=TwoWay}"
                                Text="{Binding Path=Name}"/>
     
                        </Canvas>
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
     
            <!--IsHitTestVisible="False" & Background="Transparent"
            pour le 2eme ListBox &&  son Canvas Panel host-->
            <ListBox 
     
                IsHitTestVisible="False" 
                Background="Transparent"
     
                Name="ListBoxArcs"  
                Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Path=Arcs}" >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Name="canvasArcs"
                            IsHitTestVisible="False" Background="Transparent"  
                            IsItemsHost="True" ClipToBounds="True" 
                            >
                        </Canvas>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
                <ListBox.Resources>
                    <DataTemplate 
                        DataType="{x:Type local:Arc}">
                        <Canvas  Background="Transparent" >
                            <Path
                                Stretch="None" 
                                Stroke="Black" StrokeThickness="2.0">
                                <Path.Data>
                                    <LineGeometry
                                        StartPoint="{Binding Path=Node1.Location,Mode=TwoWay}"                                       
                                        EndPoint="{Binding Path=Node2.Location,Mode=TwoWay}">
                                    </LineGeometry>
                                </Path.Data>
                            </Path>
                        </Canvas> 
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
        </Grid>
    </Window>
    code behind .cs du form allege:
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
     
    namespace WpfAppGraphNode2
    {
        /// <summary>
        /// Logique d'interaction pour Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            private SimpleGraph mygraph;
     
            public Window1()
            {
                InitializeComponent();
                mygraph = new SimpleGraph();
     
                //DATACONTEXT SUR LE GRAPH
     
                this.DataContext = mygraph;
            }
     
            //HANDLERS SANS CHANGEMENTS
     
            private Path selPath = null;
            private void canvasNodes_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                selPath = e.OriginalSource as Path;
                if (selPath == null) return;
     
                //azctiver la capture par le  path
                selPath.CaptureMouse();
     
            }
     
            private void canvasNodes_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (selPath == null) return;
                Point p = e.GetPosition(selPath);
     
                //le binding est bidirection grace à Mode=TwoWay 
                EllipseGeometry ellip = selPath.Data as EllipseGeometry;
                if (ellip == null) return;
     
                ellip.Center = p;
     
            }
     
            private void canvasNodes_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (selPath == null) return;
     
                //liberer la capture souris par un click droit 
                selPath.ReleaseMouseCapture();
     
                selPath = null;
     
            }
        }
    }
    Les Thumbs avec des Adoners pour deplacer ,resizer les Path des Nodes sont "scarces" avec des ItemsControls car il faut parcourir les ListBoxItems et retrouver les Path des Nodes situes dans les DataTemplates....

    Par contre fort ils sont fort utilles si on utilise un Canvas "hote direct" ,il suffit de placer des Adorners sur chaque children du canvas...
    Bien sur il faut ecrire du code pour le class Adorner des Nodes.....
    Bon code...

  18. #18
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    je prend tes remarques et je code.

    une idée :
    ce que je veux voir c'est une représentation d'un nœud, je peut mémoriser le reste des donnée métier dans une base de donnée métier ne comportant qu'un lien avec la représentation, comme ça je ne "consomme pas trop " lors des binding bi-directionnel, et puis il faudra interpréter un propriété "tableau BT", "transformateur", "Sectionneur" ... pour préparer le dessin ou l’icône qu'il faut.
    le test se fera sur une propriété ou un ensemble de propriétés (Transformateur + sec ou à l'huile + en service ou hors service+...) .

  19. #19
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    re

    rdh123

    ce que je veux voir c'est une représentation d'un nœud,
    Tout est possible ...
    La prop Fill du Path peut afficher un ImageBrush(binde à un image) ou DrawingGeometry (dessin en
    dialecte XAML) dans les Resources d 'Application...

    Comme l'EllipseGeometry "clippera" l'image ou le dessin....
    Il faut un RectangleGeomtry qui n'as helas de DP Point mais un DP Rect ....
    Pour le positionner bien centre sur le Location du Node (DataModel) ,il faut un class Helper auxiliaire
    designe ci-après par Ex dote de 2 DP attachées de type Point (les DP attaches ressemblent au Canvas.Letft et Canvas.Top) :
    - RectLocation pour positionner le RectangleGeometry
    - RectLocationLabel pour positionner le TextBlock d'etiquette (j'en ai profite pour adjuster la position du TextBlock)


    rdh123
    , ....et puis il faudra interpréter un propriété "tableau BT", "transformateur", "Sectionneur" ... pour préparer le dessin ou l’icône qu'il faut....
    Les DataTemplate.Triggers du DataTemplate du Node sont fait pour ca..
    A condition que tu rajoutes un prop NodeType de type NodeType (c'est un Enum à creer )...
    Les champs de l'Enum "mappe" les differents codes des Nodes du datamodel c.à.d les TG BT,TRANSFO,DISJONC,INTERSEC etc....
    Au chargement des donnees la prop NodeType se voit assigner le champ Enum approprie....
    L'enum est illustratif,on pourrait utiliser une prop NodeType de meme Type que le Code appareil en base....

    Evidemment autant d'images ou icones que les Codes Appareils doivent etre disponibles dans les Resources d'Application.....

    Bref voici le code behind .cs revu de:
    1/class Node y compris L'Enum NodeType :
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
     
     
    // enum pour le type de node à assigner lors 
        // du chargement des donnees en baase 
        public enum NodeType
        {
     
            TRFO,      // transfo
            TGBT,      // tg bt 
            BREAKER,   // disjonct
            SWITCHER   // intersec
     
        }
        public class Node : INotifyPropertyChanged
        {
     
            private int _id;
            private double _x;
            private double _y;
            public Node()
            {
                ID = 0;
                X = 100;
                Y = 75;
                NodeType = NodeType.TRFO;
            }
            public Node(double x, double y):this()
            {
                X = x;
                Y = y;
            }
            //ctor revu
            public Node(string pname, double x, double y,NodeType pcode) : this(x, y)
            {
                Name = pname;
                Location= new  Point( x,y);
                NodeType = pcode;
            }
     
     
            //----------Propriétés---
     
            public double X
            {
                get { return this._x; }
     
                set
                {
                    if (value != this._x)
                    {
                        this._x = value;
                        this.location.X = this._x; 
                        OnPropertyChanged("X");
                    }
                }
            }
     
            public double Y
            {
                get { return this._y; }
     
                set
                {
                    if (value != this._y)
                    {
                        this._y = value;
                        this.location.Y = this._y;
                        OnPropertyChanged("Y");
                    }
                }
            }
            /// <summary>
            /// rajout prop Location en double
            /// </summary>
            private Point location;
            public Point Location
            {
                get { return location; }
                set
                {
                    if (value != this.location)
                    {
                       this.location = value;
                       this._x  = this.location.X;
                       this._y  = this.location.Y;
                        OnPropertyChanged("Location");
                    }
                } 
     
            }
            private string _name;
            public string Name
            {
                get { return this._name; }
     
                set
                {
                    if (value != this._name)
                    {
                        this._name = value;
                        OnPropertyChanged("Name");
                    }
                }
            }
            public int ID
            {
                get { return this._id; }
     
                set
                {
                    if (value != this._id)
                    {
                        this._id = value;
                        OnPropertyChanged("ID");
                    }
                }
            }
     
     
     
     
            // Prop NodeType associe au Node de type Enum
            private NodeType nodeType;
            public NodeType NodeType
            {
                get { return nodeType; }
                set
                {
                    if (value != this.nodeType)
                    {
                        this.nodeType = value;
                        OnPropertyChanged("NodeType");
                    }
                }
     
            }
     
           public event PropertyChangedEventHandler PropertyChanged;
     
            private void OnPropertyChanged(String infopropriety)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(infopropriety));
                }
            }
         }
    2/SimpleGraph (GpahUtile n'est pas impacte,ainsi que RouteCity)


    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
    62
    63
    64
    65
    66
    67
     
      public class SimpleGraph : GraphUtile
        {
            private List<RouteCity> tableRoute = new List<RouteCity>();
     
            public SimpleGraph()
                : base()
            {
                tableRoute = GetRoute();
     
                foreach (RouteCity route in tableRoute)
                {
                    this.AddArc(
                        route.City1,rndPosition.X, rndPosition.Y,rndCode,
                        route.City2, rndPosition.X, rndPosition.Y, rndCode);
                }
            }
            private List<RouteCity> GetRoute()
            {
                List<RouteCity> l = new List<RouteCity> {
               new RouteCity("ROOT", "Paris"),
               new RouteCity("Paris", "Chartres"),
               new RouteCity("Chartres", "Le Mans"),
               new RouteCity("Le Mans", "Tours"),
               new RouteCity("Tours", "Nantes"),
               new RouteCity("Paris", "Dijon"),
               new RouteCity("Dijon", "Lyon"),
               new RouteCity("Paris", "Rouen"),
               new RouteCity("Paris", "Arras"),
               new RouteCity("Arras", "Lille"),
               new RouteCity("Rouen","Arras")
                };
               // List<RouteCity> l = new List<RouteCity> {
               //new RouteCity("ROOT", "Contantine"),
               //new RouteCity("Contantine", "Annaba"),
               //new RouteCity("Contantine", "Batna"),
               //new RouteCity("Contantine", "Setif"),
               //new RouteCity("Setif", "Batna"),
               //new RouteCity("Setif", "Msila"),
               //new RouteCity("Setif", "BBA"),
               //new RouteCity("Contantine", "Tebessa"),
               //new RouteCity("Guelma", "SoukAhras")
                //};
                return l;
            }
            private Random rnd = new Random();
            private Point rndPosition
            {
                get
                {
                    Point p = new Point() { X = rnd.Next(100, 500), Y = rnd.Next(100, 500) };
                    return p;
                }
            }
     
            private NodeType  rndCode
            {
                get
                {
                    int n = Enum.GetValues(typeof(NodeType)).Length;
                    int i=rnd.Next(0,n);
     
                    NodeType c =(NodeType)Enum.GetValues(typeof(NodeType)).GetValue(i);
                    return c;
                }
            }
        }
    3/ du class helper Ex
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
     
    using System;
    using System.Windows;
    using System.Windows.Shapes;
    using System.Windows.Media;
    using System.Windows.Controls;
     
    namespace WpfAppGraphNode2
    {
        // class helper pour center le rectangle 
        // utilisant une DP attachee pour center le RectangleGeometry
        public class Ex : DependencyObject
        {
            private   RectangleGeometry currentGeom = null;
     
            public Ex()
            {
     
            }
     
     
     
            public static Point GetLocationRect(DependencyObject obj)
            {
                return (Point)obj.GetValue(LocationRectProperty);
            }
     
            public static void SetLocationRect(DependencyObject obj, Point value)
            {
                obj.SetValue(LocationRectProperty, value);
            }
     
            // Using a DependencyProperty as the backing store for Point.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LocationRectProperty =
                DependencyProperty.RegisterAttached("LocationRect", 
                typeof(Point), typeof(Ex ), 
                new UIPropertyMetadata(new Point(),OnLocationRectChanged ));
            private static void OnLocationRectChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                RectangleGeometry rectGeom = d as RectangleGeometry;
                Point pt = (Point)args.NewValue ;
     
                Rect rect = rectGeom.Rect;
                rect.X = pt.X - rect.Width  / 2;
                rect.Y = pt.Y - rect.Height / 2;
                rectGeom.Rect = rect;
     
            }
     
     
     
            public static Point GetLocationLabel(DependencyObject obj)
            {
                return (Point)obj.GetValue(LocationLabelProperty);
            }
     
            public static void SetLocationLabel(DependencyObject obj, Point value)
            {
                obj.SetValue(LocationLabelProperty, value);
            }
     
            // Using a DependencyProperty as the backing store for LocationLabel.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty LocationLabelProperty =
                DependencyProperty.RegisterAttached("LocationLabel", 
                typeof(Point), typeof(Ex),
                new UIPropertyMetadata(new Point(), OnLocationLabelChanged));
            private static void OnLocationLabelChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                TextBlock tb = d as TextBlock ;
                Point pt = (Point)args.NewValue;
     
                pt.Y -=50 ; // car rectanglegeometry a une hauteur de 50...
                Canvas.SetLeft(tb,pt.X );
                Canvas.SetTop(tb,pt.Y );
     
     
            }
     
     
        }
    }

    3/ code xaml du fichier App.xaml

    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
     
    <Application x:Class="WpfAppGraphNode2.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 StartupUri="WindowBis.xaml">
        <Application.Resources>
            <!--transfo-->
            <Image x:Key="trfo"
                       Width="100"
                       Source="Images/Chrysanthemum.jpg"/>
            <!--tg bt-->
            <Image x:Key="tgbt"
                       Width="100"
                       Source="Images/Hydrangeas.jpg"/>
            <!--disj -->
            <Image x:Key="breaker"
                       Width="100"
                       Source="Images/Koala.jpg"/>
     
            <!--switcher -->
            <Image x:Key="switcher"
                       Width="100"
                       Source="Images/Tulips.jpg"/>
        </Application.Resources>
    </Application>
    3/code xaml du dernier form revu avec les modifs suivants
    -le 2e listbox des arcs est mis à l'arriere-plan et le 1er des nodes est mis à l'avant-plan
    -rajout des DataTemplate.Triggers du DataTemplate du Node
    -injection du class Ex
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
     
     
    <Window x:Class="WpfAppGraphNode2.WindowBis"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:local="clr-namespace:WpfAppGraphNode2" 
            Title="WindowBis" Height="300" Width="300">
     
         <!--Grid assure la superposistion "exacte" des 2 LisbBoxes comme 2 calques-->
        <Grid >
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <DockPanel>
                <TextBlock Text="{Binding Path=Name}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=ID}" Margin="5"></TextBlock>
                <TextBlock Text="{Binding Path=Location}" Margin="5"></TextBlock>
            </DockPanel>
     
            <!--2eme ListBox devient le premier pour cacher les connecteurs visuels des arcs 
            qui viennent chevaucher les arcs
            Background est mis à LightGray comme arriere-plan mais .....
            tu peux assigner une image (une carte geo) si tu veux !!!  -->
     
            <ListBox 
                Name="ListBoxArcs"  
                Grid.Row="1"
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Path=Arcs}" >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Name="canvasArcs"
                            IsHitTestVisible="False" Background="LightGray"   
                            IsItemsHost="True" ClipToBounds="True" 
                            >
                        </Canvas>
                    </ItemsPanelTemplate>
                </ListBox.ItemsPanel>
                <ListBox.Resources>
                    <DataTemplate 
                        DataType="{x:Type local:Arc}"
                        >
                        <Canvas  
                            Background="Transparent" >
                            <Path
                                Stretch="None" 
                                Stroke="Black" StrokeThickness="2.0">
                                <Path.Data>
                                    <LineGeometry
                                        StartPoint="{Binding Path=Node1.Location,Mode=TwoWay}"                                       
                                        EndPoint="{Binding Path=Node2.Location,Mode=TwoWay}">
                                    </LineGeometry>
                                </Path.Data>
                            </Path>
                        </Canvas>
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
            <!--le 1er ListBox devient le 2eme pour afficher les  visuels des nodes au 1er plan 
            NB : dans un Panel le (ici le Grid) le dernier element affiche passe au premier plan 
            mais la prop Bacground du C<anvas est permutee à Transparet pour voir les Connecteurs Arcs
              -->
            <ListBox 
                Grid.Row="1"
                Name="ListBoxNodes" 
                Background="Transparent"  
                IsSynchronizedWithCurrentItem="True"
                ItemsSource="{Binding Path=Nodes}" >
                <ListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas 
                            Name="canvasNodes"
                            IsItemsHost="True" ClipToBounds="True" 
                            Background="Transparent" 
                            PreviewMouseLeftButtonDown="canvasNodes_PreviewMouseLeftButtonDown"
                            PreviewMouseMove="canvasNodes_PreviewMouseMove"
                            PreviewMouseRightButtonDown="canvasNodes_PreviewMouseRightButtonDown" >
                        </Canvas>
                    </ItemsPanelTemplate>
     
                </ListBox.ItemsPanel>
     
                <ListBox.Resources>
                    <DataTemplate 
                        DataType="{x:Type local:Node}">
                        <Canvas  Background="Transparent" >
                            <Path
                                x:Name="pathNode"
                                Stretch="None"  
                                Stroke="Red" 
                               >
                                <!--injection du class Ex helper-->
                                <Path.Data>
                                    <RectangleGeometry 
                                            local:Ex.LocationRect="{Binding Path=Location}"
                                            Rect="0,0,50,50"/>
                                </Path.Data>
                            </Path>
                            <TextBlock 
                                Foreground="White"  
                                Background="RoyalBlue"  
                                local:Ex.LocationLabel="{Binding Path=Location}"
                                Text="{Binding Path=NodeType}"/>
                        </Canvas>
                        <!--les triggers du DataTemplate opinent suuvant la valeur du prop NodeType 
                        en consequence pour afficher le Image appropRiee-->
                        <DataTemplate.Triggers>
     
                            <DataTrigger Binding="{Binding Path=NodeType}" Value="TRFO" >
                                <Setter TargetName="pathNode" Property="Fill" >
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding Source={StaticResource trfo},Path=Source}" />
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=NodeType}" Value="TGBT" >
                                <Setter TargetName="pathNode" Property="Fill" >
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding Source={StaticResource tgbt},Path=Source}"  />
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=NodeType}" Value="BREAKER" >
                                <Setter TargetName="pathNode" Property="Fill">
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding Source={StaticResource breaker},Path=Source}" />
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=NodeType}" Value="SWITCHER" >
                                <Setter TargetName="pathNode" Property="Fill">
                                    <Setter.Value>
                                        <ImageBrush ImageSource="{Binding Source={StaticResource breaker},Path=Source}" />
                                    </Setter.Value>
                                </Setter>
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ListBox.Resources>
            </ListBox>
     
     
        </Grid>
    </Window>
    4/ code behind .cs revu du form (cette fois le DataContext du Path est remis à l'honneur dans MouseMove ):

    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
    62
    63
    64
    65
    66
    67
     
    namespace WpfAppGraphNode2
    {
        /// <summary>
        /// Logique d'interaction pour Window3.xaml
        /// </summary>
        public partial class WindowBis : Window
        {
            private SimpleGraph mygraph;
            public WindowBis()
            {
                InitializeComponent();
                mygraph = new SimpleGraph();
     
     
                mygraph = new SimpleGraph();
     
                //DATACONTEXT SUR LE GRAPH
     
                this.DataContext = mygraph;
            }
            private Path selPath = null;
            private void canvasNodes_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                selPath = e.OriginalSource as Path;
                if (selPath == null) return;
     
                //activer la capture par le  path
                selPath.CaptureMouse();
     
            }
     
            private void canvasNodes_PreviewMouseMove(object sender, MouseEventArgs e)
            {
                if (selPath == null) return;
                Point p = e.GetPosition(selPath);
     
                //le binding est bidirection grace à Mode=TwoWay 
                //EllipseGeometry ellip = selPath.Data as EllipseGeometry;
                //if (ellip == null) return;
     
                //ellip.Center = p;
     
                // => NOUIVEAU CODE
                Node nd = selPath.DataContext as Node;
                nd.Location = p;
     
                RectangleGeometry rectGeom = selPath.Data as RectangleGeometry;
                if (rectGeom == null) return;
     
                Ex.SetLocationRect(rectGeom, p);
     
            }
     
            private void canvasNodes_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
            {
                if (selPath == null) return;
     
                //liberer la capture souris par un click droit 
                selPath.ReleaseMouseCapture();
     
                selPath = null;
     
     
            }
        }
    }
    Les DP Attachees permettent de creer des props sur des Objets qui en sont depourves à l'origine,à une condition que la prop ait du sens pour l'objet considere....
    Ainsi elle n'as aucun sens pour Rectangle ou Ellipse bien qu'il derive tous de Shape comme Path ,Line,Polyline et Polygon ...
    Rectangle et Ellipse sont des types "autosize" alors que Path,Line , Polyline et Polygon sont de type "coordinates" ..En effet tu auras observe que Path en l'absence des Canvas.Setleft et Canvas.Top postionne en coordonnees absolues les Geometrys qu'il englobe....
    bon code...

  20. #20
    Membre régulier
    Inscrit en
    Septembre 2006
    Messages
    232
    Détails du profil
    Informations forums :
    Inscription : Septembre 2006
    Messages : 232
    Points : 94
    Points
    94
    Par défaut
    Merci MABROUKI pour ton aide si précieuse, je viens de lire et c'est super,comme je l'ais déjà annoncé je ne suis pas informaticien et donc mon job me dicte mon temps libre.

Discussions similaires

  1. [Console] developper une application pour xbox
    Par fan dans le forum Langages de programmation
    Réponses: 4
    Dernier message: 03/02/2011, 13h08
  2. Réponses: 2
    Dernier message: 21/11/2005, 09h35
  3. [JDBC] Exemple d'application pour commencer
    Par Le Pharaon dans le forum JDBC
    Réponses: 15
    Dernier message: 08/09/2005, 18h43
  4. Votre expérience en Màj applic pour client
    Par GymTonic dans le forum Access
    Réponses: 2
    Dernier message: 08/01/2005, 17h59
  5. [J2ME]Application pour SIM Card V1
    Par WOLO Laurent dans le forum Java ME
    Réponses: 3
    Dernier message: 09/11/2004, 15h26

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