I had a similar idea as S M Kamran: You can have a Canvas
property in your Shape
class to indicate the canvas to which that shape belongs to, and a Shapes
collection in your Canvas
class to hold a collection of shapes:
Here's a quick example:
interface ICanvas
{
// It's a good thing to use an interface
// in this phase. It will allow you greater
// freedom later.
}
class Canvas : ICanvas
{
private Shape.ShapeCollection _shapes;
public Collection<Shape> Shapes
{
get { return _shapes; }
}
public Canvas()
{
_shapes = new Shape.ShapeCollection(this);
}
}
class Shape
{
public class ShapeCollection : Collection<Shape>
{
private readonly ICanvas _parent;
public ShapeCollection(ICanvas parent)
{
_parent = parent;
}
protected override void InsertItem(int index, Shape item)
{
item._canvas = _parent;
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
this[index]._canvas = null;
base.RemoveItem(index);
}
protected override void SetItem(int index, Shape item)
{
RemoveAt(index);
InsertItem(index, item);
}
protected override void ClearItems()
{
while (this.Count != 0)
this.RemoveAt(this.Count - 1);
}
}
private ICanvas _canvas;
public ICanvas Canvas
{
get { return _canvas; }
}
}
By adding a shape to a canvas, Shape.Canvas
property will be updated automatically:
Canvas canvas = new Canvas();
Shape circle = new Shape();
canvas.Shapes.Add(circle);
Note that ShapeCollection
is a nested class inside Shape
, because it's the only way to set the private _canvas
property.
Generic collections (like Collection<Shape>
) are often used for similar problems, because you can override their InsertItem
/RemoveItem
properties to add custom functionality when the collection is being changed.
You can also create an "Empty/Default Canvas" singleton, and use it instead of null when shape is not assigned to a real canvas (just to avoid checking if Shape.Canvas
is null every time).