【问题标题】:How to create a custom MultiSelector / ItemsControl in WPF / C#如何在 WPF/C# 中创建自定义 MultiSelector/ItemsControl
【发布时间】:2010-11-29 15:40:09
【问题描述】:

我正在尝试在 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 DiagramItem.Location 中定义的位置。 IOW 当我更改 DiagramItem 中的 X 属性时,Diagram 会在 x 轴上移动项目。

注意: MultiSelector 是从 ItemsControl 和 Selector 派生的,只在这里使用,因为我需要显示的项目是可选择的。


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


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

  1. 有多个图表项。
  2. 用户可以选择多个图表项。
  3. 可以调整图表项的大小、旋转和拖动图表上的任何位置。
  4. 可以使用键盘在图表项之间导航。

我基本上有两个甚至三个与这个问题相关的课程。

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

Diagram.ItemsPanel 也就是显示项目的可视面板应该是支持绝对定位的面板,例如 Canvas。

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

在实现自定义 MultiSelector / ItemsControl 时必须考虑什么?


资源:

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

其他资源:

【问题讨论】:

    标签: c# wpf custom-controls itemscontrol


    【解决方案1】:

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

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

    神奇之处在于正确使用绑定,关键是将内容项添加为Source。下一步显然是处理项目的选择,但这本身就是另一个问题。

    【讨论】:

    • 没问题!很高兴我能帮上忙
    • 该行UnselectedEvent = MultiSelector.SelectedEvent.AddOwner 真的应该是UnselectedEvent = MultiSelector.UNSelectedEvent.AddOwner 吗?
    【解决方案2】:

    如果有帮助的话,我根据我的图形和图表自定义控件写了一篇代码项目文章,称为 NetworkView:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-11
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多