CAD-like WPF system - all data in classes
Still choosing the XAML / WPF learning path. If someone shows me how to accomplish the following, it will help me develop my next project (and several similar projects in the future).
Let's say I have a set of objects that define the objects to be drawn onto the canvas. Objects contain all the information needed to render objects, including shape, color, and location. Is it possible to create a XAML control that binds to this collection and handles the rendering, or is this better done by painting to the canvas in code?
One more point - objects should end up being selected by selection, lasso-rectangular and dragged. This does not need to be addressed in the sample code someone is supplying, but I thought it might be important to know about it as it might affect different implementations.
See example below. thanks in advance.
Class DrawingElement
readonly property Shape as string ("circle", "square", "triangle")
readonly property Position as point (coordinates)
readonly property Color as string ("red", "blue", "yellow")
end class
Sub Main
dim lst as new List(of DrawingElement)
lst.add(new DrawingElement("Circle", 10,20, "Blue"))
lst.add(new DrawingElement("Square", 80,35, "Red"))
lst.add(new DrawingElement("Triangle", 210,120, "Yellow"))
<draw lst!>
End Sub
source to share
It can be done, but without using magic strings (eg "circle") as in your example.
First, you should design models based on existing structure elements, not create a model with the idea of hacking new UI elements or trying to create code that interprets between them .
WPF already has an ellipse (circle), rectangle (square), and a whole host of other geometric primitives that you can use. You will want to create models that contain public binding properties that you can bind to instances of these elements to control their shape and position.
Without going into details (or testing), I would do something like this
public class GeometricElement : INotifyPropertyChanged
{
// these are simplified and don't show INPC code
public double Left {get;set;}
public double Top {get;set;}
public Brush Fill {get;set;}
// ...
}
// ...
public class Square : GeometricElement
{
public double Width {get;set;}
public double Height {get;set;}
}
// ...
// bound to the window
public class CadAppDataContext
{
public ObservableCollection<GeometricElement> Elements {get; private set;}
}
And in my xaml it would look like
<ItemsControl ItemsSource="{Binding Source={StaticResource cadAppDataContext}}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Resources>
<DataTemplate TargetType="{x:Type me:Square}">
<Rectangle
Canvas.Left="{Binding Left}"
Canvas.Top="{Binding Top}"
Width="{Binding Width}"
Height="{Binding Height}"
Fill="{Binding Fill}" />
</DataTemplate>
<!-- more DataTemplates for circle, triangle, etc etc -->
</ItemsControl.Resources>
</ItemsControl>
The ItemsControl will create a Canvas and for each GeometricElement in my collection will add a new child UI based on the type of the object in Elements.
Controls are bound to collections and can add or remove items based on what happens in the collection inside your code. It identifies a UI element to add by searching for a DataTemplate that is for a specific type. This is a common and important pattern, and this is why using magic strings will hurt you in the long run; the magic string route will prevent you from using the capabilities of the framework already built into WPF.
Now I am not saying this will work out of the box. You will likely run into properties that won't bind without some kind of heavy lifting. You may even have to extend the geometry primitives to make them behave the way you want them to. But this is the pattern used in WPF applications. Understanding the pattern and using it will help you avoid stress and setbacks.
source to share