代码之家  ›  专栏  ›  技术社区  ›  hannson

如何在wpf/c中创建自定义的multiselector/itemscontrol#

  •  1
  • hannson  · 技术社区  · 15 年前

    我正试图用c/wpf创建一个图表应用程序。我要做的是有点类似于微软的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;
                }
            }
        }
    
    //...
    

    好吧,我的想法是 图表:项控件 将其项放置在画布面板上项diagramitem.location中定义的位置。当我在一个diagram item中更改x属性时,图表会在x轴上移动该项。

    注: multiselector是从itemscontrol和selector派生的,仅在这里使用,因为我需要显示的项是可选的。


    请注意,如果可能的话,我宁愿不使用xaml。


    在长:
    用户看到的图表实例有以下要求:

    1. 有多个诊断项。
    2. 用户可以选择多个DigabrIts项。
    3. 可以在图表的任何地方调整大小,旋转和拖动。
    4. 可以使用键盘在诊断项之间导航。

    我基本上有两门课,也可能有三门课和这个问题有关。

    • 图解 扩展system.windows.controls.primitives。 多选机 :选择器:项控件
    • 图表项目 延伸 内容控制 或其他控制

    diagram.items panel也称为显示项目的可视面板,应该是支持绝对定位的面板,如 帆布 .

    我应该如何实现一个从多选择器派生的类,你能指出哪些资源与这个问题相关?

    在实现自定义multiselector/itemscontrol时需要考虑什么?


    资源:

    我发现与我的问题相关的资源很少,但我还是不确定我应该寻找什么。我已经使用reflector阅读了listbox和listboxitem的源代码,但是没有发现它非常有用。

    其他资源:

    2 回复  |  直到 8 年前
        1
  •  6
  •   hannson    15 年前

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

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

    魔术是在正确使用边框,关键是添加竞争者作为来源。下一步显然是处理项目的选择,但这本身就是另一个问题。

        2
  •  1
  •   Ashley Davis    12 年前

    如果有帮助的话,我写了一篇代码项目文章,基于我的图形和图表自定义控件networkview:

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