如何在WPF / C#中创建自定义MultiSelector / ItemsControl

时间:2009-09-18 23:28:12

标签: c# wpf custom-controls itemscontrol

我正在尝试在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;
            }
        }
    }

//...

好的,所以我的想法是 Diagram:ItemsControl 将其项放置在Canvas面板上Item ItemItem.Location中定义的位置。 IOW当我在DiagramItem中更改X属性时,Diagram会在x轴上移动项目。

注意: MultiSelector派生自ItemsControl和Selector,仅在此使用,因为我需要显示的项目可供选择。


请注意,如果可能,我不想使用xaml。


长期:
用户看到的Diagram实例具有以下要求:

  1. 有多个DiagramItems。
  2. 用户可以选择多个DiagramItems。
  3. 可以在图表的任何位置调整图表项目的大小,旋转和拖动。
  4. 可以使用键盘在DiagramItems之间导航。
  5. 我基本上有两个,可能还有三个与这个问题相关的课程。

    • 图表扩展了System.Windows.Controls.Primitives。 MultiSelector :Selector:ItemsControl
    • DiagramItem 扩展 ContentControl 或其他一些控件

    Diagram.ItemsPanel又称显示项目的可视面板应该是支持绝对定位的面板,如画布

    我应该如何实现从MultiSelector派生的类,以及您可以指出哪些资源与此问题相关?

    实现自定义MultiSelector / ItemsControl时需要考虑什么?


    资源:

    我发现很少有与我的问题相关的资源,但是我再也不确定我应该寻找什么。我已经使用Reflector读取了ListBox和ListBoxItem的源代码,但没有发现它非常有用。

    其他资源:

2 个答案:

答案 0 :(得分:6)

好的,显然这可以通过使用绑定和属性框架轻松实现。

    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,关键是将contentitem添加为Source。下一步显然是处理项目的选择,但这是另一个问题。

答案 1 :(得分:1)

如果有任何帮助,我根据我的图形和图表自定义控件编写了一个代码项目文章,名为NetworkView:

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