Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

Tout sur WPF, LINQ, C# et .NET en général !

[WPF] Comment créer des éléments déplaçables et interconnectés entre eux ?

Pour essayer de comprendre ce que je veux dire, essayer de vous représenter un diagramme de classe: il s'agit de simple rectangle qui sont reliés entre eux Smile

Imaginez maintenant que vous souhaitiez faire la même chose, mais que vous puissiez également déplacer chacun de ces rectangles: vous seriez en mesure de pouvoir commencer à réaliser des applications dans le même esprit que Visio par exemple Wink

Attention, il faut bien faire en sorte que les lignes reliant les rectangles se déplacent également sinon, l'affichage ne serait pas logique.

Je vous avais déjà expliqué, dans un précédent post, comment faire en sorte de pouvoir déplacer des éléments au sein d'une application WPF (Windows Presentation Foundation).

J'ai donc repris ce code dans un petit contrôle (héritant de Shape) et je l'ai un peu amélioré:

public class MoveableRectangle : Shape

    {

        private bool isDragging;

        private Point controlPoint, mousePoint, newMousePoint;

 

        private List<ConnectionLine> m_ConnectionLineCollection;

 

        public List<ConnectionLine> ConnectionLineCollection

        {

            get { return m_ConnectionLineCollection; }

            set { m_ConnectionLineCollection = value; }

        }

 

 

        public MoveableRectangle()

        {

            this.m_ConnectionLineCollection = new List<ConnectionLine>();

        }

 

        /// <summary>

        /// Propriété utilisée pour indiquer quelle type de forme sera affichée.

        /// </summary>

        protected override Geometry DefiningGeometry

        {

            get

            {

                return new RectangleGeometry(new Rect(new Size(this.Width, this.Height)));

            }

        }

 

        protected override void OnMouseDown(MouseButtonEventArgs e)

        {

            base.OnMouseDown(e);

 

            isDragging = true;

 

            controlPoint = new Point(Canvas.GetLeft(this), Canvas.GetTop(this));

            mousePoint = new Point(Mouse.GetPosition((IInputElement)this.Parent).X, Mouse.GetPosition((IInputElement)this.Parent).Y);

        }

 

        protected override void OnMouseMove(MouseEventArgs e)

        {

            base.OnMouseMove(e);

 

            if (isDragging == true)

            {

                newMousePoint = new Point(Mouse.GetPosition((IInputElement)this.Parent).X, Mouse.GetPosition((IInputElement)this.Parent).Y);

 

                Canvas.SetLeft(this, (controlPoint.X + newMousePoint.X - mousePoint.X));

                Canvas.SetTop(this, (controlPoint.Y + newMousePoint.Y - mousePoint.Y));

 

                foreach (ConnectionLine line in this.m_ConnectionLineCollection)

                {

                    switch (line.ConnectionLineDirection)

                    {

                        case ConnectionLine.LineDirection.Start:

                            line.ConnectedLine.X1 = Canvas.GetLeft(this);

                            line.ConnectedLine.Y1 = Canvas.GetTop(this);

                            break;

 

                        case ConnectionLine.LineDirection.End:

                            line.ConnectedLine.X2 = Canvas.GetLeft(this);

                            line.ConnectedLine.Y2 = Canvas.GetTop(this);

                            break;

 

                        default:

                            break;

                    }

                }

            }

        }

 

        protected override void OnMouseUp(MouseButtonEventArgs e)

        {

            base.OnMouseUp(e);

 

            isDragging = false;

        }

    }

Le code est quasi-identique à la version d'avant, hormis 2 différences:

  • l'appel à this.Parent (caster en IInputElement)
  • l'ajout d'un foreach permettant de repositionner les lignes reliant les rectangles entre eux.

Je ne vous fais pas l'explication du code, celui-ci devant être assez simple à comprendre Smile Il ne nous reste plus, à présent, qu'à utiliser notre contrôle au sein de notre application WPF:

<Canvas>

    <MyControl:MoveableRectangle x:Name="rect"

                        Width="70"

                        Height="40"

                        Fill="Red"

                        Canvas.Top="15"

                        Canvas.Left="45" />

 

    <Line X1="45" Y1="15" X2="95" Y2="145" Stroke="Black" StrokeThickness="1" x:Name="line" />

 

    <MyControl:MoveableRectangle x:Name="rect2"

                        Width="70"

                        Height="40"

                        Fill="Blue"

                        Canvas.Top="145"

                        Canvas.Left="95" />

 

    <Line X1="95" Y1="145" X2="150" Y2="200" Stroke="Black" StrokeThickness="1" x:Name="line2" />

 

    <MyControl:MoveableRectangle x:Name="rect3"

                        Width="70"

                        Height="40"

                        Fill="Orange"

                        Canvas.Top="200"

                        Canvas.Left="150" />

</Canvas>

Là encore, rien de bien compliqué. Là où cela se corse, c'est qu'il nous faut un moyen pour indiquer à notre contrôle qu'il est relié à un (ou plusieurs) autre éléments. Et c'est à cela que sert la propriété ConnectionLineCollection que j'ai ajouté au contrôle. Pour vous aider à comprendre comment cela fonctionne, j'ai mis des commentaires:

// 1 ligne relie 2 rectangles: on indique le rectangle de départ et le rectangle d'arrivée.

// Rectangle de départ: X1-Y1 de la ligne

// Rectangle d'arrivéet: X2-Y2 de la ligne            this.rect.ConnectionLineCollection.Add(new ConnectionLine(this.line, ConnectionLine.LineDirection.Start));

this.rect2.ConnectionLineCollection.Add(new ConnectionLine(this.line, ConnectionLine.LineDirection.End));

 

 this.rect2.ConnectionLineCollection.Add(new ConnectionLine(this.line2, ConnectionLine.LineDirection.Start));

 this.rect3.ConnectionLineCollection.Add(new ConnectionLine(this.line2, ConnectionLine.LineDirection.End));

 Au final, on obtient bien ce que l'on souhaite, comme vous pouvez le constater sur cette image (si elle ne bouge pas, cliquez sur l'image pour la voir s'animer):

Certes, ce n'est pas optimum (il y aurait 2-3 améliorations à faire pour ce soit mieux) mais cela vous permet de comprendre le principe Smile

Si vous souhaitez télécharger la source d'exemple, c'est par ici: http://morpheus.developpez.com/wpf/tools/MoveAndLinkElements.zip

 

En espérant que cela vous aide ;)

 

 

A+

 

PS: Bon Nix, à quand un endroit où je peux poster mes sources WPF sur CodeS-SourceS ? Wink

 

 

del.icio.us Tags:

Technorati Tags:
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: lundi 6 août 2007 19:51 par Thomas LEBRUN
Classé sous : , ,

Commentaires

Matthieu MEZIL a dit :

Excellent post Thomas.

Pour avoir déjà fait ce genre de chose sans WPF, j'apprécie d'autant plus...

# août 10, 2007 12:28

Bidou a dit :

Pour poster les codes en WPF sur CS, c'est ici:

http://www.csharpfr.com/codes_categorie/WPF/350.aspx

:-)

# avril 8, 2008 09:43
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- [Refactoring] ReSharper pour Visual Studio 2010 (Preview) par Thomas Jaskula le il y a 11 heures et 1 minutes

- [Refactoring] Analyser vos exceptions avec ReSharper Exceptional par Thomas Jaskula le il y a 12 heures et 15 minutes

- SharePoint 2007 : patterns & practices SharePoint Guidance par Philippe Sentenac [MVP SharePoint] le 07-03-2009, 09:56

- [Visual Studio 2010] Les tests cases c’est bien, mais je vais devoir tout réécrire ? par Etienne Margraff le 07-03-2009, 09:00

- MVP[Gribouillon].AddYear par The Grib's Lair [Sébastien PICAMELOT - MVP SharePoint] le 07-03-2009, 08:45

- Clinique INSIA - Projet de fin d’Etudes (Silverlight 3 MVVM et OutOfBrowser, WCF, TFS) - Part 1 par David REI le 07-02-2009, 23:38

- C’est la crise ? Bah pourquoi cramer du budget pub alors ? par Nix's Blog le 07-02-2009, 15:31

- Soyons MVP ! par TheSaib .NET blog le 07-02-2009, 12:15

- SharePoint : Gestion des Erreurs 6398, 7076 et 6482 par Blog Technique de Romelard Fabrice le 07-02-2009, 11:53

- EF avec WPF par Matthieu MEZIL le 07-02-2009, 10:18