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 :

Différentes profondeurs de plan pour des objets surperposés dans un Canvas


Sujet :

Windows Presentation Foundation

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

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Points : 3 580
    Points
    3 580
    Par défaut Différentes profondeurs de plan pour des objets surperposés dans un Canvas
    Bonjour,
    Mon souci est simple, j'ai un canvas dans lequel je dessine des objets, et je veux afficher une combobox pour permettre de choisir l'échelle.
    Et cette combobox n'apparaît pas, elle semble être derrière ma figure dessinée (qui pourtant n'est pas sensée passer par dessus).

    Code XML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <Graphics:DrawMyObject x:Name="myObject" Background="Transparent">
       <ComboBox Name="ComboBoxMyObject" Height="25" Canvas.Top="148" Canvas.Left="-173" Canvas.ZIndex="2">
          <ComboBoxItem IsSelected="True">...</ComboBoxItem>
       </ComboBox>
    </Graphics:DrawMyObject>

    Mon objet DrawMyObject hérite d'une classe DrawObject, qui dérive elle même de DrawingCanvas (qui dérive de canvas donc) que j'ai pris sur internet.

    Voici ma classe DrawObject :
    Code C# : 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
    public abstract class DrawObject : DrawingCanvas
        {
            public Dictionary<string, DrawObject> Childs { get; set; }
            protected DrawingCanvas canvasChilds;
            public DrawObject parent;
            protected Pen pen;
            public DrawingVisual thisDraw;
     
            public DrawObject(DrawObject parent)
            {
                this.parent = parent;
                InstanciePen();
                Childs = new Dictionary<string, DrawObject>();
                thisDraw = new DrawingVisual();
                canvasChilds = new DrawingCanvas();
                AddVisual(thisDraw);
                AddVisual(canvasChilds);
                update();
            }
     
            abstract protected void InstanciePen();
     
            abstract protected DrawingVisual DrawVisual(DrawingVisual visual);
     
            protected void DrawObjectStruc()
            {
                thisDraw = DrawVisual(thisDraw);
            }
     
            public void update()
            {
                DrawObjectStruc();
                canvasChilds.ClearVisuals();
                foreach (DrawObject o in Childs.Values) {
                    o.update();
                    canvasChilds.AddVisual(o);
                }
            }
        }

    L'idée est donc d'avoir une série de figure qui contiennent elle même d'autres figures. Je débute complétement à la fois en .NET et en conception d'interfaces graphiques alors ce n'est peut être pas le moyen le plus propre de faire cela.

    Et la classe DrawingCanvas :
    Code C# : 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
    public class DrawingCanvas : Canvas
        {
            private List<Visual> visuals = new List<Visual>();
            private List<DrawingVisual> hits = new List<DrawingVisual>();
     
            protected override int VisualChildrenCount
            {
                get { return visuals.Count; }
            }
     
            protected override Visual GetVisualChild(int index)
            { return visuals[index]; }
     
            public void AddVisual(Visual visual)
            {
                visuals.Add(visual);
                base.AddVisualChild(visual);
                base.AddLogicalChild(visual);
            }
     
            public void DeleteVisual(Visual visual)
            {
                visuals.Remove(visual);
                base.RemoveVisualChild(visual);
                base.RemoveLogicalChild(visual);
            }
     
            public void ClearVisuals()
            {
                foreach (Visual v in visuals) {
                    base.RemoveVisualChild(v);
                    base.RemoveLogicalChild(v);
                }
                visuals.Clear();
            }
     
            public DrawingVisual GetVisual(Point point)
            {
                HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
                return hitResult.VisualHit as DrawingVisual;
            }
     
            public List<DrawingVisual> GetVisuals(Geometry region)
            {
                hits.Clear();
                GeometryHitTestParameters parameters = new GeometryHitTestParameters(region);
                HitTestResultCallback callback = new HitTestResultCallback(this.HitTestCallback);
                VisualTreeHelper.HitTest(this, null, callback, parameters);
                return hits;
            }
     
            private HitTestResultBehavior HitTestCallback(HitTestResult result)
            {
                GeometryHitTestResult geometryResult = (GeometryHitTestResult)result;
                DrawingVisual visual = result.VisualHit as DrawingVisual;
     
                // Only include matches that are DrawingVisual objects and
                // that are completely inside the geometry.
                if (visual != null && geometryResult.IntersectionDetail == IntersectionDetail.FullyInside)
                {
                    hits.Add(visual);
                }
                return HitTestResultBehavior.Continue;
            }

    En tant que débutant .NET, j'avoue ne pas avoir tout compris, notamment cette histoire de hit...

    Mon problème est donc le suivant : pourquoi lorsque mes figures se dessinent dans mon DrawMyObject, ma combobox n'apparaît-elle pas ?
    (au début j'ai pensé qu'elle était derrière, mais l'ajout du ZIndex ne change rien)

  2. #2
    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 442
    Points
    4 442
    Par défaut do not overrides VisualChildrenCount & GetVisualChild
    bonjour Flaburgan
    Si tu overrides ces 2 methodes ci-dessous comme tu l'as fait , plus aucun controle type UIelement "reactif" ne sera visible .Seuls les "inertes" DrawingVisual seront visibles puisque ils sont "freezable" c.a.d non reactifs.
    ton code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // à virer et revoir l'architecture des classes
     protected override int VisualChildrenCount
            {
                get { return visuals.Count; }
            }
     
            protected override Visual GetVisualChild(int index)
            { return visuals[index]; }
    Quant au HitTestResult c'est un test d'atteinte "geometrique" specifique aux
    DrawingVisual(ancetre ContainerVisual) car ils sont depourvus de "reactivite"(events,binding...) .Ce sont des "Freezable" inertes.
    Les controles eux sont dotes de "reactivite" entre autres les "geometriques" comme Rectangle ,Ellipse ,polygone et consorts derives de la classe abstraite Shape heritable au passage.....
    Pour le reste je n'ai pas bien saisi la logique des tes classes et en particulier comment se fait la creation d'un nouvel DrawingVisual sur le canvas (par :
    - DrawingVisual.RenderOpen ou bien
    --OnRender(ByVal drawingContext As DrawingContext)
    Si tu veux garder les 2 methodes ci-dessus ,il y a l'approche qui consiste à dedier la classe controle canvas uniquement au dessin d'elements drawingvisuals .
    Tout controle menu,boite à outils et tutti quanti..... au dehors .
    Bon code...

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

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Points : 3 580
    Points
    3 580
    Par défaut
    Bonjour et merci de venir me donner un coup de main.
    Comme je l'ai dit, ce n'est pas moi qui ai écrit DrawingCanvas, et à vrai dire je ne comprends pas comment elle fonctionne. Telle que je m'en servais, je n'utilisais pas les deux méthodes que tu citais ci-dessus. Je ne faisais qu'ajouter des Visuels, et quand je ne voulais mettre à jour je faisais un clear de tous les visuels et j'ajoutais à nouveau ceux dont j'avais besoin.
    J'ai donc pu mettre les deux méthodes ci-dessus en commentaire. Ma combobox apparaît alors, mais plus rien ne se dessine à côté.

    Tu as l'air de dire que je ne peux pas interagir avec mes visuels si j'override ces deux méthodes (je ne saisi pas pourquoi, mais je suppose qu'elles servent au bon fonctionnement de cette réaction en temps normal). C'est plutôt embêtant pour moi car j'imaginais plus tard pouvoir cliquer sur mes formes pour les retirer du dessin. Je pense donc que DrawingCanvas, en tout cas en l'état, ne correspond pas à mon besoin. L'embêtant, c'est que les formes que je souhaite dessiner sont plus complexe qu'une simple ellipse ou un simple rectangle. Et il est aussi important de pouvoir naviguer parmi chacune jusqu'à atteindre celle que je souhaite (d'où les dictionnaires).
    Alors, que dois-je utiliser ?

  4. #4
    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 442
    Points
    4 442
    Par défaut 2 voies possibles :classe geometry et shape ou DrawingVisual
    Bonjour Flaburgan
    Ne me fait pas dire ce que je n'ai pas dit:tu peux interagir avec tes visuels de type Visual ....avec du code helas.... à gerer par ton controle "Hote" DrawMyObject avec l'aide du test d'atteinte geometrique de VisualTreeHelperTest ....donc devoir coder.....
    Pourquoi les controles disparaissent de la vue: tes 2 methodes overrides renvoient des Visuals pas des FrameWorkElement.
    Maintenant le seul moyen de voir ta Combobox c'est de mettre(wrapper) DrawMyObject lui-meme dans un Canvas et positionner le ComboBox dans ce dernier Canvas ainsi que d'autre controles dont tu aurais besoin.
    Comme illustre dans cet exemple MSDN Doc pour les DrawingVisuals(dans cet exemple ton DrawMyObject s'appelle plutot MyVisualHost)
    code behind du projet WinForm:
    Code C# : 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
     
    using System;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
     
    namespace SDKSample
    {
        public partial class Window1 : Window
        {
             private void WindowLoaded(object sender, EventArgs e)
             {
                 MyVisualHost visualHost = new MyVisualHost();
                 MyCanvas.Children.Add(visualHost);
             }
         }
     
        //<Snippet100> 
        //Il faut declarer- ici c'est fait par code-un controle hote pour heberger les "visuals" dans notre cas
        //des objets DrawingVisual
        // Create a host visual derived from the FrameworkElement class.
        // This class provides layout, event handling, and container support for
        // the child visual objects.
        // NotaBene:le controle hote peut etre un canvas personnalise realise ailleurs.   
        // mais il est contenu dans le canvas declare dans Window.Xaml
        public class MyVisualHost : FrameworkElement
        {
            // Create a collection of child visual objects.
            private VisualCollection _children;
     
            public MyVisualHost()
            {
                _children = new VisualCollection(this);
                _children.Add(CreateDrawingVisualRectangle());
                _children.Add(CreateDrawingVisualText());
                _children.Add(CreateDrawingVisualEllipses());
     
                // Add the event handler for MouseLeftButtonUp.
                this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MyVisualHost_MouseLeftButtonUp);
            }
            //</Snippet100> 
     
            //<Snippet103> 
            // Capture the mouse event and hit test the coordinate point value against
            // the child visual objects.
            void MyVisualHost_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
                // Retreive the coordinates of the mouse button event.
                Point pt = e.GetPosition((UIElement)sender);
     
                // Initiate the hit test by setting up a hit test result callback method.
                VisualTreeHelper.HitTest(this, null, new HitTestResultCallback(myCallback), new PointHitTestParameters(pt));
            }
     
            // If a child visual object is hit, toggle its opacity to visually indicate a hit.
            public HitTestResultBehavior myCallback(HitTestResult result)
            {
                if (result.VisualHit.GetType() == typeof(DrawingVisual))
                {
                    if (((DrawingVisual)result.VisualHit).Opacity == 1.0)
                    {
                        ((DrawingVisual)result.VisualHit).Opacity = 0.4;
                    }
                    else
                    {
                        ((DrawingVisual)result.VisualHit).Opacity = 1.0;
                    }
                }
     
                // Stop the hit test enumeration of objects in the visual tree.
                return HitTestResultBehavior.Stop;
            }
            //</Snippet103> 
     
            //<Snippet101> 
            // Create a DrawingVisual that contains a rectangle.
            private DrawingVisual CreateDrawingVisualRectangle()
            {
                DrawingVisual drawingVisual = new DrawingVisual();
     
                // Retrieve the DrawingContext in order to create new drawing content.
                DrawingContext drawingContext = drawingVisual.RenderOpen();
     
                // Create a rectangle and draw it in the DrawingContext.
                Rect rect = new Rect(new Point(160, 100), new Size(320, 80));
                drawingContext.DrawRectangle(Brushes.LightBlue, (Pen)null, rect);
     
                // Persist the drawing content.
                drawingContext.Close();
     
                return drawingVisual;
            }
            //</Snippet101> 
     
            //<Snippet110> 
            // Create a DrawingVisual that contains text.
            private DrawingVisual CreateDrawingVisualText()
            {
                // Create an instance of a DrawingVisual.
                DrawingVisual drawingVisual = new DrawingVisual();
     
                // Retrieve the DrawingContext from the DrawingVisual.
                DrawingContext drawingContext = drawingVisual.RenderOpen();
     
                // Draw a formatted text string into the DrawingContext.
                drawingContext.DrawText(
                   new FormattedText("Click Me!",
                      CultureInfo.GetCultureInfo("en-us"),
                      FlowDirection.LeftToRight,
                      new Typeface("Verdana"),
                      36, Brushes.Black),
                      new Point(200, 116));
     
                // Close the DrawingContext to persist changes to the DrawingVisual.
                drawingContext.Close();
     
                return drawingVisual;
            }
            //</Snippet110> 
     
            // Create a DrawingVisual that contains an ellipse.
            private DrawingVisual CreateDrawingVisualEllipses()
            {
                DrawingVisual drawingVisual = new DrawingVisual();
                DrawingContext drawingContext = drawingVisual.RenderOpen();
     
                drawingContext.DrawEllipse(Brushes.Maroon, null, new Point(430, 136), 20, 20);
                drawingContext.Close();
     
                return drawingVisual;
            }
     
            //<Snippet102>
     
            //<Snippet102a>
            // Provide a required override for the VisualChildrenCount property.
            protected override int VisualChildrenCount
            {
                get { return _children.Count; }
            }
            //</Snippet102a>
     
            //<Snippet102b>
            // Provide a required override for the GetVisualChild method.
            protected override Visual GetVisualChild(int index)
            {
                if (index < 0 || index > _children.Count)
                {
                    throw new ArgumentOutOfRangeException();
                }
     
                return _children[index];
            }
            //</Snippet102b>
     
            //</Snippet102> 
        }
    }

    code xaml du projet winform:
    Code XML : 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
     
    <Window
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      x:Class="SDKSample.Window1"
      Title="DrawingVisual Example"
      Width="640"
      Height="480"
      Loaded="WindowLoaded"
      Background="Beige"
      >
     
      <StackPanel>
        <TextBlock TextWrapping="Wrap" Margin="20" FontSize="12">
               This sample shows how to use DrawingVisual objects -- 
               in this case, a rectangle, text, and circle object. 
               The three DrawingVisual objects displayed below are 
               contained by a user-defined host visual object.
     
               Although the DrawingVisual objects do not support event handling, 
               the host visual object can handle events and provide hit testing
               for the child DrawingVisual objects. Try clicking 
               on all three DrawingVisual objects -- the opacity value switches
               between 1.0 and 0.4 on a successful hit test for the object.</TextBlock>
        <Canvas Name="MyCanvas" Width="640" Height="480" 
                  Background="Cornsilk">
                <Button >BoutonSurMyCanvas</Button>
        </Canvas>
      </StackPanel>
    </Window>

    Maintenant il existe une autre approche de dessin utilisant la classe Geometry ,Path dont herite les fameux controles Rectangle,Ellipse ,Line etc....
    Voici un premier exemple (ou toute la gestion dragging moving....est faite avec la souris) mais n'empeche pas le controle BoutonVisible d'etre "visible".
    code behind du projet winform:
    Code C# : 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
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
     
     
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Shapes;
    using System.Xml;
    using System.Windows.Markup;
    namespace  Interactive2DDrawing
    {
    public partial class Interactive2DDrawing : Window
        {
            private List<Path> paths = new List<Path>();
            private Point startPoint = new Point();
            private Shape rubberBand = null;
            Point currentPoint = new Point();
            private bool isDragging = false;
            private bool isDown = false;
            private Path originalElement = new Path();
            private Path movingElement = new Path();
            private Path path1 = new Path();
            private Path path2 = new Path();
            private SolidColorBrush fillColor =
            new SolidColorBrush();
            private SolidColorBrush borderColor =
            new SolidColorBrush();
            private SolidColorBrush selectFillColor =
            new SolidColorBrush();
            private SolidColorBrush selectBorderColor =
            new SolidColorBrush();
        public Interactive2DDrawing()
            {
                InitializeComponent();
                fillColor.Color = Colors.LightGray;
                fillColor.Opacity = 0.5;
                borderColor.Color = Colors.Gray;
                selectFillColor.Color = Colors.LightCoral;
                selectFillColor.Opacity = 0.5;
                selectBorderColor.Color = Colors.Red;
            }
        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
            if (!canvas1.IsMouseCaptured)
                {
                    startPoint = e.GetPosition(canvas1);
                    canvas1.CaptureMouse();
                    if (rbCombine.IsChecked == true)
                    {
                        if (canvas1 == e.Source)
                            return; 
                        SetCombineShapes(e);
                    }
                    else if (rbSelect.IsChecked == true)
                    {
                        if (canvas1 == e.Source)
                            return;
                        isDown = true;
                        originalElement = (Path)e.Source;
                        e.Handled = true;
                    }
                    else if (rbDelete.IsChecked == true)
                    {
                        if (canvas1 == e.Source)
                            return;
                        originalElement = (Path)e.Source;
                        DeleteShape(originalElement);
                    }
                }
            }
        private void DeleteShape(Path path)
            {
                path.Stroke = selectBorderColor;
                string msg =
                "Do you really want to delete this shape?";
                string title = "Delete Shape?";
                MessageBoxButton buttons = MessageBoxButton.YesNo;
                MessageBoxImage icon = MessageBoxImage.Warning;
                MessageBoxResult result =
                MessageBox.Show(msg, title, buttons, icon);
                if (result == MessageBoxResult.Yes)
                    canvas1.Children.Remove(path);
                else
                {
                    path.Stroke = borderColor;
                    return;
                }
            }
        private void SetCombineShapes(MouseButtonEventArgs e)
            {
                if (path1.Name != "path1Selected")
                {
                    path1 = (Path)e.Source;
                    path1.Cursor = Cursors.Hand;
                    path1.Stroke = selectBorderColor;
                    path1.Name = "path1Selected";
                }
                else
                {
                    if (path2 != null)
                    {
                        path2.Stroke = borderColor;
                        path2.Cursor = Cursors.Arrow;
                    }
                    path2 = (Path)e.Source;
                    path2.Cursor = Cursors.Hand;
                    path2.Stroke = selectBorderColor;
                    ContextMenu cm = new ContextMenu();
                    path2.ContextMenu = cm;
                    MenuItem mi = new MenuItem();
                    mi.Header = "Union";
                    mi.Click +=
                    new RoutedEventHandler(Union_Click);
                    cm.Items.Add(mi);
                    mi = new MenuItem();
                    mi.Header = "Xor";
                    mi.Click +=
                    new RoutedEventHandler(Xor_Click);
                    cm.Items.Add(mi);
                    mi = new MenuItem();
                    mi.Header = "Intersect";
                    mi.Click +=
                    new RoutedEventHandler(Intersect_Click);
                    cm.Items.Add(mi);
                    mi = new MenuItem();
                    mi.Header = "Exclude";
                    mi.Click +=
                    new RoutedEventHandler(Exclude_Click);
                    cm.Items.Add(mi);
                }
            }
        private void Union_Click(object sender, RoutedEventArgs e)
            {
            CombineShapes(path1, path2, "Union");
            path1.Name = "";
            }
        private void Xor_Click(object sender,RoutedEventArgs e)
            {
            CombineShapes(path1, path2, "Xor");
            path1.Name = "";
            }
        private void Intersect_Click(object sender,RoutedEventArgs e)
            {
                CombineShapes(path1, path2, "Intersect");
                path1.Name = "";
            }
        private void Exclude_Click(object sender,RoutedEventArgs e)
            {
                CombineShapes(path1, path2, "Exclude");
                path1.Name = "";
            }
        private void CombineShapes(Path p1, Path p2, string s)
            {
                Path myPath = new Path();
                myPath.Fill = fillColor;
                myPath.Stroke = borderColor;
                CombinedGeometry cg = new CombinedGeometry();
                if (s == "Union")
                    cg.GeometryCombineMode =
                    GeometryCombineMode.Union;
                else if (s == "Xor")
                    cg.GeometryCombineMode =
                    GeometryCombineMode.Xor;
                else if (s == "Intersect")
                    cg.GeometryCombineMode =
                    GeometryCombineMode.Intersect;
                else if (s == "Exclude")
                    cg.GeometryCombineMode =
                    GeometryCombineMode.Exclude;
                cg.Geometry1 = p1.Data;
                cg.Geometry2 = p2.Data;
                myPath.Data = cg;
                paths.Add(myPath);
                canvas1.Children.Add(paths[paths.Count - 1]);
                canvas1.Children.Remove(p1);
                canvas1.Children.Remove(p2);
            }
        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (canvas1.IsMouseCaptured)
            {
                currentPoint = e.GetPosition(canvas1);
                if (rubberBand == null)
                {
                    rubberBand = new Rectangle();
                    rubberBand.Stroke = Brushes.LightCoral;
                    rubberBand.StrokeDashArray =
                    new DoubleCollection(new double[] { 4, 2 });
                    if (rbSquare.IsChecked == true ||
                    rbRectangle.IsChecked == true ||
                    rbCircle.IsChecked == true ||
                    rbEllipse.IsChecked == true)
                    {
                        canvas1.Children.Add(rubberBand);
                    }
                }
                double width = Math.Abs(
                startPoint.X - currentPoint.X);
                double height = Math.Abs(
                startPoint.Y - currentPoint.Y);
                double left = Math.Min(
                startPoint.X, currentPoint.X);
                double top = Math.Min(
                startPoint.Y, currentPoint.Y);
                rubberBand.Width = width;
                rubberBand.Height = height;
                Canvas.SetLeft(rubberBand, left);
                Canvas.SetTop(rubberBand, top);
                if (rbSelect.IsChecked == true)
                {
                    if (isDown)
                    {
                        if (!isDragging && Math.Abs(currentPoint.X - startPoint.X) >
                        SystemParameters.MinimumHorizontalDragDistance &&
                        Math.Abs(currentPoint.Y - startPoint.Y) >
                        SystemParameters.MinimumVerticalDragDistance)
                            DragStarting();
                        if (isDragging)
                            DragMoving();
                    }
                }
            }
        }
     
        private void OnMouseLeftButtonUp(object sender,MouseButtonEventArgs e)
            {
                if (rbSquare.IsChecked == true)
                    AddSquare(startPoint, currentPoint);
                else if (rbRectangle.IsChecked == true)
                    AddRectangle(startPoint, currentPoint);
     
                else if (rbCircle.IsChecked == true)
                    AddCircle(startPoint, currentPoint);
     
                else if (rbEllipse.IsChecked == true)
                    AddEllipse(startPoint, currentPoint);
     
                if (rubberBand != null)
                {
                    canvas1.Children.Remove(rubberBand);
                    rubberBand = null;
                    canvas1.ReleaseMouseCapture();
                }
     
                if (rbSelect.IsChecked == true)
                {
                    if (isDown)
                    {
                        DragFinishing(false);
                        e.Handled = true;
                    }
                }
            }
        private void AddRectangle(Point pt1, Point pt2)
            {
                Path path = new Path();
                path.Fill = fillColor;
                path.Stroke = borderColor;
                RectangleGeometry rg = new RectangleGeometry();
                double width = Math.Abs(pt1.X - pt2.X);
                double height = Math.Abs(pt1.Y - pt2.Y);
                double left = Math.Min(pt1.X, pt2.X);
                double top = Math.Min(pt1.Y, pt2.Y);
                rg.Rect = new Rect(left, top, width, height);
                path.Data = rg;
                paths.Add(path);
                canvas1.Children.Add(paths[paths.Count - 1]);
            }
        private void AddSquare(Point pt1, Point pt2)
            {
                Path path = new Path();
                path.Fill = fillColor;
                path.Stroke = borderColor;
                RectangleGeometry rg = new RectangleGeometry();
                double width = Math.Abs(pt1.X - pt2.X);
                double height = Math.Abs(pt1.Y - pt2.Y);
                double left = Math.Min(pt1.X, pt2.X);
                double top = Math.Min(pt1.Y, pt2.Y);
                double side = width;
                if (width > height)
                side = height;
                rg.Rect = new Rect(left, top, side, side);
                path.Data = rg;
                paths.Add(path);
                canvas1.Children.Add(paths[paths.Count - 1]);
            }
     
        private void AddCircle(Point pt1, Point pt2)
            {
                 Path path = new Path();
                path.Fill = fillColor;
                path.Stroke = borderColor;
                EllipseGeometry eg = new EllipseGeometry();
                double width = Math.Abs(pt1.X - pt2.X);
                double height = Math.Abs(pt1.Y - pt2.Y);
                double left = Math.Min(pt1.X, pt2.X);
                double top = Math.Min(pt1.Y, pt2.Y);
                double side = width;
                if (width > height)
                side = height;
                eg.Center = new Point(left + side / 2,
                top + side / 2);
                eg.RadiusX = side / 2;
                eg.RadiusY = side / 2;
                path.Data = eg;
                paths.Add(path);
                canvas1.Children.Add(paths[paths.Count - 1]);
            }
        private void AddEllipse(Point pt1, Point pt2)
            {
                Path path = new Path();
                path.Fill = fillColor;
                path.Stroke = borderColor;
                EllipseGeometry eg = new EllipseGeometry();
                double width = Math.Abs(pt1.X - pt2.X);
                double height = Math.Abs(pt1.Y - pt2.Y);
                double left = Math.Min(pt1.X, pt2.X);
                double top = Math.Min(pt1.Y, pt2.Y);
                eg.Center = new Point(left + width / 2,
                top + height / 2);
                eg.RadiusX = width / 2;
                eg.RadiusY = height / 2;
                path.Data = eg;
                paths.Add(path);
                canvas1.Children.Add(paths[paths.Count - 1]);
            }
        private void DragStarting()
            {
                isDragging = true;
                movingElement = new Path();
                movingElement.Data = originalElement.Data;
                movingElement.Fill = selectFillColor;
                movingElement.Stroke = selectBorderColor;
                canvas1.Children.Add(movingElement);
            }
        private void DragMoving()
            {
                currentPoint = Mouse.GetPosition(canvas1);
                TranslateTransform tt = new TranslateTransform();
                tt.X = currentPoint.X - startPoint.X;
                tt.Y = currentPoint.Y - startPoint.Y;
                movingElement.RenderTransform = tt;
            }
        private void DragFinishing(bool cancel)
            {
                Mouse.Capture(null);
                if(isDragging)
                {
                    if (!cancel)
                    {
                        currentPoint = Mouse.GetPosition(canvas1);
                        TranslateTransform tt0 = new TranslateTransform();
                        TranslateTransform tt = new TranslateTransform();
                        tt.X = currentPoint.X - startPoint.X;
                        tt.Y = currentPoint.Y - startPoint.Y;
                        Geometry geometry =
                        (RectangleGeometry)new RectangleGeometry();
                        string s = originalElement.Data.ToString();
                        if (s == "System.Windows.Media.EllipseGeometry")
                            geometry = (EllipseGeometry)originalElement.Data;
                        else if (s == "System.Windows.Media.RectangleGeometry")
                            geometry = (RectangleGeometry)originalElement.Data;
                        else if (s == "System.Windows.Media.CombinedGeometry")
                            geometry = (CombinedGeometry)originalElement.Data;
                        if (geometry.Transform.ToString()!= "Identity")
                        {
                            tt0 = (TranslateTransform)geometry.Transform;
                            tt.X += tt0.X;
                            tt.Y += tt0.Y;
                        }
                        geometry.Transform = tt;
                        canvas1.Children.Remove(originalElement);
                        originalElement = new Path();
                        originalElement.Fill = fillColor;
                        originalElement.Stroke = borderColor;
                        originalElement.Data = geometry;
                        canvas1.Children.Add(originalElement);
                    }
                    canvas1.Children.Remove(movingElement);
                    movingElement = null;
                }
                isDragging = false;
                isDown = false;
            }
        }
    }
    code xaml du projet winform:
    Code XML : 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
     
    <Window x:Class="InteractiveDrawing.Interactive2DDrawing"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Dessin 2D" Height="400" Width="400">
     
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <ToolBarTray Grid.Row="0">
                <ToolBar>
                    <RadioButton x:Name="rbSquare"
                                 IsChecked="True" ToolTip="Add Square">
                        <Rectangle Width="15" Height="15"
                                 Stroke="Blue" Fill="LightBlue"/>
                    </RadioButton>
                    <RadioButton x:Name="rbRectangle"
                                 IsChecked="False" ToolTip="Add Rectangle">
                        <Rectangle Width="20" Height="12"
                                    Stroke="Blue" Fill="LightBlue"/>
                    </RadioButton>
                    <RadioButton x:Name="rbCircle"
                                 IsChecked="False" ToolTip="Add Circle">
                        <Ellipse Width="18" Height="18"
                                 Stroke="Blue" Fill="LightBlue"/>
                    </RadioButton>
                    <RadioButton x:Name="rbEllipse"
                                 IsChecked="False" ToolTip="Add Ellipse">
                        <Ellipse Width="22" Height="15"
                                 Stroke="Blue" Fill="LightBlue"/>
                    </RadioButton>
                    <RadioButton x:Name="rbCombine"
                                 IsChecked="False" ToolTip="Combine shapes">
                        <Path Fill="LightBlue" Stroke="Blue">
                            <Path.Data>
                                <CombinedGeometry>
                                    <CombinedGeometry.Geometry1>
                                        <EllipseGeometry
                                            RadiusX="8"
                                            RadiusY="8"
                                            Center="8,8"/>
                                    </CombinedGeometry.Geometry1>
                                    <CombinedGeometry.Geometry2>
                                        <EllipseGeometry
                                            RadiusX="8"
                                            RadiusY="8"
                                            Center="20,8"/>
                                    </CombinedGeometry.Geometry2>
                                </CombinedGeometry>
                            </Path.Data>
                        </Path>
                    </RadioButton>
                    <RadioButton x:Name="rbSelect"
                                 IsChecked="False" ToolTip="Select/Move">
                        <Polygon
                                Points="6 1,10 1,10 10,14 10,8 16,2 10,6 10"
                                Fill="LightBlue" Stroke="Blue">
                            <Polygon.RenderTransform>
                                <RotateTransform CenterX="8"
                                                 CenterY="8"
                                                 Angle="225"/>
                            </Polygon.RenderTransform>
                        </Polygon>
                    </RadioButton>
                    <RadioButton x:Name="rbDelete"
                                 IsChecked="False" ToolTip="Delete">
                        <Grid>
                            <Line X1="2" Y1="2" X2="14"
                                  Y2="14" Stroke="Blue"/>
                            <Line X1="2" Y1="14" X2="14"
                                  Y2="2" Stroke="Blue"/>
                        </Grid>
                    </RadioButton>
                </ToolBar>
            </ToolBarTray>
            <Viewbox Stretch="Uniform" Grid.Row="1">
                    <Border Margin="5" BorderBrush="Black"
                            BorderThickness="1" Grid.Row="1"
                            HorizontalAlignment="Left">
                            <Canvas Name="canvas1" Width="400"
                                    Height="345" ClipToBounds="True"
     
                                    MouseLeftButtonDown="OnMouseLeftButtonDown"
                                    MouseLeftButtonUp="OnMouseLeftButtonUp"
                                    MouseMove="OnMouseMove" 
                                    Background="White" 
                                    >
                                    <Button Height="21.109" Canvas.Left="273.306" Canvas.Top="32.219" Width="73.326">BoutonVisible</Button>
     
                    </Canvas>
     
                </Border>
            </Viewbox>
        </Grid>
    </Window>
    Sur la meme veine voici un autre exemple ou les figures sont ajoutes en xaml mais la gestion precedente des objets(dragging, moving, dropping, and deleting shapes more efficiently using the HitTest method) peut etre faite en utilisant VisualTreeHelperTest qui est efficace et evite une gestion de mouvement souris.
    Mais a cause du VisualTreeHelperTest qui utilise les "visuels" pour le test et donc nos 2 methodes en coulisses il faut wrapper le canvas dans un canvas externe ou sera positionne le ComboBox.

    code behind du projet winform:
    Code C# : 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
     
    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.Navigation;
    using System.Windows.Shapes;
     
    namespace Wpf2DHitTest
    {
        /// <summary>
        /// Logique d'interaction pour Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            private List<Rectangle> hitList = new List<Rectangle>();
            private EllipseGeometry hitArea = new EllipseGeometry();
            public Window1()
            {
                InitializeComponent();
                Initialize();
            }
     
     
            private void Initialize()
            {
                foreach (Rectangle rect in canvas1.Children)
                {
                    rect.Fill = Brushes.LightBlue;
                }
            }
            private void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                // Initialization:
                Initialize();
                // Get mouse click point:
                Point pt = e.GetPosition(canvas1);
                // Define hit-testing area:
                hitArea = new EllipseGeometry(pt, 1.0, 1.0);
                hitList.Clear();
                // Call HitTest method:
                VisualTreeHelper.HitTest(canvas1, null,
                new HitTestResultCallback(HitTestCallback),
                new GeometryHitTestParameters(hitArea));
                if (hitList.Count > 0)
                {
                    foreach (Rectangle rect in hitList)
                    {
                        // Change rectangle fill color if it is hit:
                        rect.Fill = Brushes.LightCoral;
                    }
                    MessageBox.Show("You hit " +
                    hitList.Count.ToString() + " rectangles.");
                }
            }
     
            public HitTestResultBehavior HitTestCallback(
            HitTestResult result)
            {
                // Retrieve the results of the hit test.
                IntersectionDetail intersectionDetail =
                    ((GeometryHitTestResult)result).IntersectionDetail;
                switch (intersectionDetail)
                {
                    case IntersectionDetail.FullyContains:
                        // Add the hit test result to the list:
                        // l'ellipse de selection  pleinement contenu contenu dans figure-ajouter
                        // on gere ce cas
                        hitList.Add((Rectangle)result.VisualHit);
                        return HitTestResultBehavior.Continue;
                    case IntersectionDetail.Intersects:
                        // Set the behavior to return visuals at all z-order levels:
                        // l'ellipse de selection  intersecte une figure (quel que soit le niveau de figure)  
                        // continuer le HitTest
                        return HitTestResultBehavior.Continue;
                    case IntersectionDetail.FullyInside:
                        // Set the behavior to return visuals at all z-order levels:
                        // l'ellipse de selection est plus grande que figure (quel que soit le niveau de figure) 
                        // continuer le HitTest
                    return HitTestResultBehavior.Continue;
                    default:
                        return HitTestResultBehavior.Stop;
                }
            }
     
     
        }
    }
    code xaml du projet winform:
    Code XML : 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
     
    <Window x:Class="Wpf2DHitTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="HitTestExample" Height="300" Width="300">
        <!--ce canevas externe permet d'afficher le combobox-->
        <Canvas  Name="canvasExterne" Width="250" Height="250" 
                 ClipToBounds="True" Background="White">
                <ComboBox 
                    Canvas.Left="150"
                    Canvas.Top="20" 
                    Height="25" 
                    Name="comboBox1" 
                    Width="50" />
                <Canvas x:Name="canvas1"
                        MouseLeftButtonDown="canvas1_MouseLeftButtonDown">
                    <Rectangle  
                        Canvas.Left="70" Canvas.Top="50"
                        Width="100" Height="60"
                        Stroke="Black" Fill="LightBlue"
                        Opacity="0.7"/>
                <Rectangle 
                        Canvas.Left="150" Canvas.Top="80"
                        Width="100" Height="60"
                        Stroke="Black" Fill="LightBlue"
                        Opacity="0.7"/>
                <Rectangle 
                        Canvas.Left="20" Canvas.Top="100"
                        Width="50" Height="50"
                        Stroke="Black" Fill="LightBlue"
                        Opacity="0.7"/>
                <Rectangle 
                        Canvas.Left="40" Canvas.Top="60"
                        Width="50" Height="50"
                        Stroke="Black" Fill="LightBlue"
                        Opacity="0.7"/>
                <Rectangle 
                        Canvas.Left="30" Canvas.Top="130"
                        Width="50" Height="50"
                        Stroke="Black" Fill="LightBlue"
                        Opacity="0.7"/>
     
                </Canvas>
        </Canvas>
    </Window>
    En resume les classes graphiques en WPF (mis à part celle derivee directement de shape qui est un controle) ne sont pas des controles mais sont "inertes" comme en WinForm ou la reactivite est gere par le developpeur.
    Sauf que en Wpf l'api graphique est plus riche ,par exemple les classe graphiques peuvent etre animees (heritent de la classe Animatable),disposent de liste pour les gerer(tu n'as pas besoin de dictionnaire sauf un dictionnaire qui gerait tes donnees personnalisees) .

    bon code..............

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

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

    Informations forums :
    Inscription : Avril 2010
    Messages : 1 229
    Points : 3 580
    Points
    3 580
    Par défaut
    Ton exemple avec les Drawing Canvas est très similaire à ce que j'ai moi, à deux différences près : Les DrawingVisual sont tous au même niveau, et non pas imbriqué sur plusieurs couches comme je l'ai fait. Cela risque-t-il de compliquer mon interaction avec l'utilisateur ?
    Mon premier Canvas qui contient ma combobox est déjà un DrawingCanvas. C'est de la que vient le problème concernant son affichage donc ?

    J'ai voulu maintenir la même hiérarchie que j'avais dans mes données dans mon affichage afin de les mettre à jour plus facilement, mais il me semble peut être plus simple de calquer mon affichage sur ton exemple : un premier canvas qui contient tous mes contrôles dont un unique DrawingCanvas qui contient toutes mes formes géométriques.

Discussions similaires

  1. [WD-2007] Différentes profondeurs de listes pour le sommaire ?
    Par Golard dans le forum VBA Word
    Réponses: 3
    Dernier message: 04/11/2013, 09h45
  2. Réponses: 4
    Dernier message: 06/06/2011, 21h05
  3. ORACLE 10 : changer d'OWNER pour des objets
    Par lediz dans le forum SQL
    Réponses: 2
    Dernier message: 09/07/2007, 15h59
  4. Recuperation des objet ole dans une base SQL
    Par TOPGUN89 dans le forum MS SQL Server
    Réponses: 7
    Dernier message: 25/11/2005, 09h14
  5. [MFC]arriere plan pour un objet de la classe CStatic
    Par gabriel knight dans le forum MFC
    Réponses: 13
    Dernier message: 28/07/2003, 10h42

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