Вопрос

Я пытаюсь создать приложение для построения диаграмм на C#/WPF.То, что я собираюсь сделать, чем-то похоже на Microsoft Visio, хотя я не пытаюсь его клонировать.Я как бы написал этот вопрос во время написания кода и просто изложил в нем все проблемы, которые у меня возникли, на случай, если кто-то найдет это полезным.Возможно, я слишком много думал, но мне кажется, что я мог бы блевать на клавиатуре и писать код получше, поэтому не стесняйтесь давать любые предложения по каждой уловленной вами детали (грамматика исключена :-))

Суммируя:
Почему все элементы расположены в (0,0)?

Код:

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;
            }
        }
    }

//...

Итак, идея в том, что Диаграмма:Элементы управления помещает свой элемент на панель Canvas в позицию, определенную в Item DiagramItem.Location.IOW, когда я меняю свойство X в DiagramItem, Diagram перемещает элемент по оси X.

Примечание: MultiSelector является производным от ItemsControl и Selector и используется здесь только потому, что мне нужно, чтобы отображаемый элемент можно было выбрать.


Обратите внимание, что я бы предпочел не использовать xaml, если это возможно.


В долгосрочном плане:
Экземпляр диаграммы, видимый пользователю, имеет следующие требования:

  1. Имеет несколько элементов DiagramItems.
  2. Пользователь может выбрать несколько элементов DiagramItems.
  3. Размер элементов DiagramItem можно изменять, поворачивать и перетаскивать в любое место диаграммы.
  4. Можно перемещаться между элементами DiagramItem с помощью клавиатуры.

По сути, у меня есть два, а возможно, и три класса, имеющих отношение к этому вопросу.

  • Диаграмма расширяет System.Windows.Controls.Primitives.Мультиселектор :Селектор:Элементы управления
  • Элемент диаграммы простирается КонтентКонтроль или какой-то другой контроль

Diagram.ItemsPanel, также известная как визуальная панель, отображающая элементы, должна быть панелью, поддерживающей абсолютное позиционирование, например Холст.

Как мне реализовать класс, производный от MultiSelector, и какие ресурсы вы можете указать, имеющие отношение к этому вопросу?

Что нужно учитывать при реализации пользовательского MultiSelector/ItemsControl?


Ресурсы:

Я нашел очень мало ресурсов, имеющих отношение к моей проблеме, но опять же, я не уверен, что мне следует искать.Я прочитал исходный код ListBox и ListBoxItem с помощью Reflector, но не нашел его очень полезным.

Другие источники:

Это было полезно?

Решение

Хорошо, очевидно, этого можно легко добиться, используя привязки и структуру свойств.

    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;
            }
        }

    }

Волшебство заключается в правильном использовании Bingings, ключом было добавить элемент контента в качестве источника.Следующим шагом, очевидно, будет обработка выбора элементов, но это уже другой вопрос.

Другие советы

Если это вам поможет, я написал статью о проекте кода на основе моего пользовательского элемента управления графиками и диаграммами под названием NetworkView:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top