han*_*son 2 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;
}
}
}
//...
Run Code Online (Sandbox Code Playgroud)
好的,所以想法是: Diagram:ItemsControl将其项放置在Canvas面板上Item ItemItem.Location中定义的位置.IOW当我在DiagramItem中更改X属性时,Diagram会在x轴上移动项目.
注意: MultiSelector派生自ItemsControl和Selector,仅在此处使用,因为我需要显示的项目是可选的.
请注意,如果可能,我不想使用xaml.
总之:
用户看到的Diagram实例具有以下要求:
我基本上有两个,可能还有三个与这个问题相关的课程.
Diagram.ItemsPanel又称显示项目的可视面板应该是支持绝对定位的面板,如Canvas.
我应该如何实现从MultiSelector派生的类,以及您可以指出哪些资源与此问题相关?
实现自定义MultiSelector/ItemsControl时需要考虑什么?
资源:
我发现很少有与我的问题相关的资源,但是我再也不确定我应该寻找什么.我已经使用Reflector读取了ListBox和ListBoxItem的源代码,但是没有发现它非常有用.
其他资源:
好吧,显然这可以通过使用绑定和属性框架轻松实现.
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
神奇的是正确使用Bingings,关键是将contentitem添加为Source.下一步显然是处理项目的选择,但这是另一个问题.