Question

J'essaie de créer une application de création de diagrammes en C # / WPF. Ce que je vais faire est un peu similaire à Microsoft Visio bien que je n’essaye pas de le cloner. J'ai en quelque sorte écrit cette question pendant que je codais et je mettais simplement tous les problèmes que j'avais dans le cas où quelqu'un trouverait cela utile. J’ai peut-être trop réfléchi, mais j’ai l’impression que je pourrais utiliser mon clavier pour produire un meilleur code. N'hésitez donc pas à faire des suggestions sur chaque détail que vous attrapez (grammaire exclue: -))

En bref:
Pourquoi tous les éléments sont-ils positionnés à (0,0)?

Code:

public class Diagram : MultiSelector
{
    public Diagram()
    {
        this.CanSelectMultipleItems = true;

        // The canvas supports absolute positioning
        FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas)); 
        this.ItemsPanel = new ItemsPanelTemplate(panel);


        // Tells the container where to position the items
        this.ItemContainerStyle = new Style();
        this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
        this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
    }

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        FrameworkElement contentitem = element as FrameworkElement;
        Binding leftBinding = new Binding("X");
        Binding topBinding = new Binding("Y");
        contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
        contentitem.SetBinding(Canvas.TopProperty, topBinding);
        base.PrepareContainerForItemOverride(element, item);
    }

    public class DiagramItem : ContentControl
    {
        private Point _location;

        public DiagramItem()
        {
        }

        static DiagramItem()
        {

        }

        public Point Location
        {
            get { return _location; }
            set
            {
                _location = value;

            }
        }

        public double X
        {
            get { return _location.X; }
            set
            {
                _location.X = value;
            }
        }

        public double Y
        {
            get { return _location.Y; }
            set
            {
                _location.Y = value;
            }
        }
    }

//...

Ok, l’idée est que Diagram: ItemsControl place son élément sur un panneau Canevas à la position définie dans l’élément DiagramItem.Location. IOW lorsque je modifie la propriété X dans un DiagramItem, le diagramme déplace l'élément sur l'axe des x.

Remarque: MultiSelector est dérivé de ItemsControl et Selector et n'est utilisé ici que parce que j'ai besoin que l'élément affiché soit sélectionnable.

Veuillez noter que je préférerais ne pas utiliser xaml si possible.

Dans le long:
Une instance de diagramme vue par l'utilisateur a les exigences suivantes:

  1. possède plusieurs objets de diagramme.
  2. L'utilisateur peut sélectionner plusieurs éléments de diagramme.
  3. Les éléments de diagramme peuvent être redimensionnés, pivotés et déplacés n’importe où sur le diagramme.
  4. Possibilité de naviguer entre les éléments de diagramme à l'aide du clavier.

J'ai essentiellement deux et peut-être trois classes pertinentes pour cette question.

  • Schéma étend System.Windows.Controls.Primitives. MultiSelector : Selector: ItemsControl
  • DiagramItem étend ContentControl ou un autre contrôle

Le panneau Diagram.ItemsPanel, autrement dit le panneau visuel qui affiche les éléments, doit être un panneau prenant en charge le positionnement absolu, comme le canevas .

Comment dois-je implémenter une classe dérivée de MultiSelector et quelles ressources pouvez-vous indiquer qui sont pertinentes pour cette question?

Que faut-il prendre en compte lors de l'implémentation d'un MultiSelector / ItemsControl personnalisé?

Ressources:

J'ai trouvé très peu de ressources pertinentes pour mon problème, mais là encore, je ne suis pas sûr de ce que je suis censé rechercher. J'ai lu le code source de ListBox et ListBoxItem à l'aide de Reflector, mais je ne l'ai pas trouvé très utile.

Autres ressources:

Était-ce utile?

La solution

OK, apparemment, cela peut être facilement réalisé en utilisant des liaisons et le framework de propriétés.

    public class Diagram : MultiSelector
    {
        public Diagram()
        {
           this.CanSelectMultipleItems = true;


            // The canvas supports absolute positioning
            FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas)); 
            this.ItemsPanel = new ItemsPanelTemplate(panel);


            // Tells the container where to position the items
           this.ItemContainerStyle = new Style();
            this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
            this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
        }


        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            FrameworkElement contentitem = element as FrameworkElement;

            Binding leftBinding = new Binding("XProperty");
            leftBinding.Source = contentitem;

            Binding topBinding = new Binding("YProperty");
            topBinding.Source = contentitem;

            contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
            contentitem.SetBinding(Canvas.TopProperty, topBinding);
            base.PrepareContainerForItemOverride(element, item);
        }





 public class DiagramItem : ContentControl
 {
       public static readonly DependencyProperty XProperty;
       public static readonly DependencyProperty YProperty;
       public static readonly RoutedEvent SelectedEvent;
       public static readonly RoutedEvent UnselectedEvent;
       public static readonly DependencyProperty IsSelectedProperty;

       public DiagramItem()
       {
       }

       static DiagramItem()
       {
            XProperty = DependencyProperty.Register("XProperty", typeof(Double), typeof(DiagramItem));
            YProperty = DependencyProperty.Register("YProperty", typeof(Double), typeof(DiagramItem));
            SelectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
            UnselectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
            IsSelectedProperty = MultiSelector.IsSelectedProperty.AddOwner(typeof(DiagramItem));

       }


       public Double X
       {
            get
            {
                return (Double)this.GetValue(XProperty);
            }

            set
            {
                this.SetValue(XProperty, value);
            }
       }

       public Double Y
       {
            get
            {
                return (Double)this.GetValue(YProperty);
            }
            set
            {
                 this.SetValue(YProperty, value);
            }
        }

        public Point Location
        {
            get
            {
                return new Point(X, Y);
            }

            set
            {
                this.X = value.X;
                this.Y = value.Y;
            }
        }

    }

La magie réside dans l'utilisation correcte de Bingings, la clé consistait à ajouter le contenu comme Source. La prochaine étape consiste évidemment à gérer le choix des éléments, mais c’est une autre question en soi.

Autres conseils

Si vous avez besoin d'aide, j'ai écrit un article de projet de code basé sur mon contrôle personnalisé de création de graphiques et de diagrammes appelé NetworkView:

http: // www. codeproject.com/Articles/182683/NetworkView-A-WPF-custom-control-for-visualizing-a

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top