Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

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

Actualités

[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

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01

- SharePoint Online: Script PowerShell pour supprimer une colonne dans tous les sites d’une collection par Blog Technique de Romelard Fabrice le 11-27-2018, 18:01