I'm trying to create a diagramming application in C# / WPF. What I going for is somewhat similar to Microsoft Visio although I'm not trying to clone it. I kind of wrote this question as I was coding and just put all the issues I had into it in case someone will find it useful. Maybe I've been thinking too hard but I feel like I could throw up on my keyboard and produce better code, so feel free to give any suggestions on every detail you catch (grammar excluded :-))
In short:
Why are all the items positioned at (0,0)?
Code:
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;
}
}
}
Ok, so the idea is that the Diagram : ItemsControl places its item on a Canvas panel at the position defined in the Item DiagramItem.Location. IOW when I change the X property in a DiagramItem the Diagram moves the item on the x-axis.
Note: MultiSelector is derived from ItemsControl and Selector and is only used here because I need the displayed item to be selectable.
Please note that I'd prefer not to use xaml if possible.
In long:
A Diagram instance as seen by the user has these requirements:
- Has multiple DiagramItems.
- User can select multiple DiagramItems.
- DiagramItems can be resized, rotated and dragged anywhere on the Diagram.
- Possible to navigate between DiagramItems using the keyboard.
I basically have two and possibly three classes relevant to this question.
- Diagram extends System.Windows.Controls.Primitives.MultiSelector : Selector : ItemsControl
- DiagramItem extends ContentControl or some other Control
The Diagram.ItemsPanel aka the visual panel which displays the items should be a panel which supports absolute positioning, like the Canvas.
How should I implement a class derived from MultiSelector and what resources can you point at which are relevant to this question?
What does one have to consider when implementing a custom MultiSelector / ItemsControl?
Resources:
I've found very few resources relevant to my issue, but then again I'm not sure what I'm supposed to be looking for. I've read the source code for ListBox and ListBoxItem using Reflector but didn't find it very useful.
Other resources: